import java.util.Base64; /** * * @author tcmdon@utu.fi * */ public class LoraAppMsg { /** * Modes of operation. */ public static final short LIGHT = 1; public static final short TEMP_HUMID = 2; public static final short TEMP_HUMID_LIGHT = 3; /** * Message lengths */ public static final short LIGHT_LEN = 1 + 3 + 1; public static final short TEMP_HUMID_LEN = 1 + 9 + 1; public static final short TEMP_HUMID_LIGHT_LEN = 1 + 12 + 1; /* * constants for interpreting sensorError field */ public static final short SUCCESS = 0; public static final short HUMID_ERROR = 1; public static final short TEMP_ERROR = 2; public static final short LIGHT_ERROR = 4; short mode; double humid; double temp; double tempIndex; double light; short sensorError;// (error / success) for individual sensor readings public static LoraAppMsg parse(String base64Encoded) { LoraAppMsg appMsg = new LoraAppMsg(); byte[] msg = Base64.getDecoder().decode(base64Encoded); if (msg.length > 0) { appMsg.mode = msg[0]; boolean ok = checkLength(appMsg.mode, msg.length); if (!ok) { throw new RuntimeException("msg mode - msg length mismatch."); } } else { throw new RuntimeException("empty app msg."); } if (appMsg.mode == TEMP_HUMID) { appMsg.humid = readDouble(msg[1], msg[2], msg[3]); appMsg.temp = readDouble(msg[4], msg[5], msg[6]); appMsg.tempIndex = readDouble(msg[7], msg[8], msg[9]); appMsg.sensorError = msg[10]; } else if (appMsg.mode == LIGHT) { appMsg.light = readDouble(msg[1], msg[2], msg[3]); appMsg.sensorError = msg[4]; } else if (appMsg.mode == TEMP_HUMID_LIGHT) { appMsg.humid = readDouble(msg[1], msg[2], msg[3]); appMsg.temp = readDouble(msg[4], msg[5], msg[6]); appMsg.tempIndex = readDouble(msg[7], msg[8], msg[9]); appMsg.light = readDouble(msg[10], msg[11], msg[12]); appMsg.sensorError = msg[13]; } return appMsg; } private static boolean checkLength(short mode, int length) { if (mode == TEMP_HUMID) { return length == TEMP_HUMID_LEN; } else if (mode == LIGHT) { return length == LIGHT_LEN; } else if (mode == TEMP_HUMID_LIGHT) { return length == TEMP_HUMID_LIGHT_LEN; } return false; } /* * x,y * 6 HEX digits * 1 : sign * 2, 3, 4 : x * 5, 6 : y */ private static double readDouble(byte b1, byte b2, byte b3) { int sign = ((b1 >> 4) == 0) ? 1 : -1; b1 &= 0b00001111; int x = (b1 << 8) | b2; int y = b3; double d = Double.valueOf(String.valueOf(x) + "." + String.valueOf(y)); d = d * sign; return d; } boolean isError() { return sensorError != SUCCESS; } boolean isHumidError() { return (sensorError & HUMID_ERROR) != SUCCESS; } boolean isTempError() { return (sensorError & TEMP_ERROR) != SUCCESS; } boolean isLightError() { return (sensorError & LIGHT_ERROR) != SUCCESS; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(" MOP: "); sb.append(mode); if (mode == LIGHT) { sb.append(" Light: "); sb.append(isLightError() ? "SENSOR ERROR" : light); } else if (mode == TEMP_HUMID) { sb.append(" Humidity: "); sb.append(isHumidError() ? "SENSOR ERROR" : humid); sb.append(" Temperature: "); sb.append(isTempError() ? "SENSOR ERROR" : temp); sb.append(" Heat Index: "); sb.append(isTempError() ? "SENSOR ERROR" : tempIndex); } else if (mode == TEMP_HUMID_LIGHT) { sb.append(" Light: "); sb.append(isLightError() ? "SENSOR ERROR" : light); sb.append(" Humidity: "); sb.append(isHumidError() ? "SENSOR ERROR" : humid); sb.append(" Temperature: "); sb.append(isTempError() ? "SENSOR ERROR" : temp); sb.append(" Heat Index: "); sb.append(isTempError() ? "SENSOR ERROR" : tempIndex); } return sb.toString(); } }