/** * Copyright (c) 2010-2016 by the respective copyright holders. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package org.openhab.binding.maxcube.internal.message; import java.io.UnsupportedEncodingException; import org.apache.commons.codec.binary.Base64; import org.openhab.binding.maxcube.internal.Utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * The C message contains configuration about a MAX! device. * * @author Andreas Heil (info@aheil.de) * @since 1.4.0 */ public final class C_Message extends Message { private static final Logger logger = LoggerFactory.getLogger(C_Message.class); private String rfAddress = null; private int length = 0; private DeviceType deviceType = null; private String serialNumber = null; private String tempComfort = null; private String tempEco = null; private String tempSetpointMax = null; private String tempSetpointMin = null; private String tempOffset = null; private String tempOpenWindow = null; private String durationOpenWindow = null; private String decalcification = null; private String valveMaximum = null; private String valveOffset = null; private String programData = null; private String boostDuration = null; private String boostValve = null; public C_Message(String raw) { super(raw); logger.debug(" *** C-Message ***"); String[] tokens = this.getPayload().split(Message.DELIMETER); rfAddress = tokens[0]; byte[] bytes = Base64.decodeBase64(tokens[1].getBytes()); int[] data = new int[bytes.length]; for (int i = 0; i < bytes.length; i++) { data[i] = bytes[i] & 0xFF; } length = data[0]; if (length != data.length - 1) { logger.debug("C_Message malformed: wrong data length. Expected bytes {}, actual bytes {}", length, data.length - 1); } String rfAddress2 = Utils.toHex(data[1], data[2], data[3]); if (!rfAddress.toUpperCase().equals(rfAddress2.toUpperCase())) { logger.debug("C_Message malformed: wrong RF address. Expected address {}, actual address {}", rfAddress.toUpperCase(), rfAddress2.toUpperCase()); } deviceType = DeviceType.create(data[4]); serialNumber = getSerialNumber(bytes); if (deviceType == DeviceType.HeatingThermostatPlus || deviceType == DeviceType.HeatingThermostat || deviceType == DeviceType.WallMountedThermostat) { parseHeatingThermostatData(bytes); } if (deviceType == DeviceType.EcoSwitch || deviceType == DeviceType.ShutterContact) { logger.trace("Device {} type {} Data:", rfAddress, deviceType.toString(), parseData(bytes)); } } private String getSerialNumber(byte[] bytes) { byte[] sn = new byte[10]; for (int i = 0; i < 10; i++) { sn[i] = bytes[i + 8]; } try { return new String(sn, "UTF-8"); } catch (UnsupportedEncodingException e) { logger.debug("Cannot encode serial number from C message due to encoding issues."); } return ""; } private String parseData(byte[] bytes) { if (bytes.length <= 18) { return ""; } try { int DataStart = 18; byte[] sn = new byte[bytes.length - DataStart]; for (int i = 0; i < sn.length; i++) { sn[i] = bytes[i + DataStart]; } logger.trace("DataBytes: " + Utils.getHex(sn)); try { return new String(sn, "UTF-8"); } catch (UnsupportedEncodingException e) { logger.debug("Cannot encode device string from C message due to encoding issues."); } } catch (Exception e) { logger.debug(e.getMessage()); logger.debug(Utils.getStackTrace(e)); } return ""; } private void parseHeatingThermostatData(byte[] bytes) { try { int plusDataStart = 18; int programDataStart = 11; tempComfort = Float.toString(bytes[plusDataStart] / 2); tempEco = Float.toString(bytes[plusDataStart + 1] / 2); tempSetpointMax = Float.toString(bytes[plusDataStart + 2] / 2); tempSetpointMin = Float.toString(bytes[plusDataStart + 3] / 2); logger.debug("DeviceType: {}", deviceType.toString()); logger.debug("RFAddress: {}", rfAddress); logger.debug("Temp Comfort: {}", tempComfort); logger.debug("TempEco: {}", tempEco); logger.debug("Temp Setpoint Max: {}", tempSetpointMax); logger.debug("Temp Setpoint Min: {}", tempSetpointMin); if (bytes.length < 211) { // Device is a WallMountedThermostat programDataStart = 4; logger.trace("WallThermostat byte {}: {}", bytes.length - 3, Float.toString(bytes[bytes.length - 3] & 0xFF)); logger.trace("WallThermostat byte {}: {}", bytes.length - 2, Float.toString(bytes[bytes.length - 2] & 0xFF)); logger.trace("WallThermostat byte {}: {}", bytes.length - 1, Float.toString(bytes[bytes.length - 1] & 0xFF)); } else { // Device is a HeatingThermostat(+) tempOffset = Double.toString((bytes[plusDataStart + 4] / 2) - 3.5); tempOpenWindow = Float.toString(bytes[plusDataStart + 5] / 2); durationOpenWindow = Float.toString(bytes[plusDataStart + 6]); boostDuration = Float.toString(bytes[plusDataStart + 7] & 0xFF >> 5); boostValve = Float.toString((bytes[plusDataStart + 7] & 0x1F) * 5); decalcification = Float.toString(bytes[plusDataStart + 8]); valveMaximum = Float.toString(bytes[plusDataStart + 9] & 0xFF * 100 / 255); valveOffset = Float.toString(bytes[plusDataStart + 10] & 0xFF * 100 / 255); logger.debug("Temp Offset: {}", tempOffset); logger.debug("Temp Open Window: {}", tempOpenWindow); logger.debug("Duration Open Window: {}", durationOpenWindow); logger.debug("Duration Boost: {}", boostDuration); logger.debug("Boost Valve Pos: {}", boostValve); logger.debug("Decalcification: {}", decalcification); logger.debug("ValveMaximum: {}", valveMaximum); logger.debug("ValveOffset: {}", valveOffset); } programData = ""; int ln = 13 * 6; // first day = Sat String startTime = "00:00h"; for (int char_idx = plusDataStart + programDataStart; char_idx < (plusDataStart + programDataStart + 26 * 7); char_idx++) { if (ln % 13 == 0) { programData += "\r\n Day " + Integer.toString((ln / 13) % 7) + ": "; startTime = "00:00h"; } int progTime = (bytes[char_idx + 1] & 0xFF) * 5 + (bytes[char_idx] & 0x01) * 1280; int progMinutes = progTime % 60; int progHours = (progTime - progMinutes) / 60; String endTime = Integer.toString(progHours) + ":" + String.format("%02d", progMinutes) + "h"; programData += startTime + "-" + endTime + " " + Double.toString(bytes[char_idx] / 4) + "C "; startTime = endTime; char_idx++; ln++; } logger.debug("ProgramData: {}", programData); } catch (Exception e) { logger.debug(e.getMessage()); logger.debug(Utils.getStackTrace(e)); } return; } public String getSerialNumber() { return serialNumber; } @Override public MessageType getType() { return MessageType.C; } public String getRFAddress() { return rfAddress; } public DeviceType getDeviceType() { return deviceType; } @Override public void debug(Logger logger) { logger.debug("=== C_Message === "); logger.trace("\tRAW: {}", this.getPayload()); logger.debug("DeviceType: {}", deviceType.toString()); logger.debug("SerialNumber: {}", serialNumber); logger.debug("RFAddress: {}", rfAddress); } }