[powermax] Improve debugging in message classes (#9314)

* Improve debugging in message classes
Each PowermaxBaseMessage subclass had its own toString() which added
useful debug info but duplicated a lot of the logic in the message
handler. I've moved the debug info inline and removed the duplication,
and also added decoding for more values to the debug output.
* Fix for 0xFF byte values, which convert to int -1
* Change to inline debug messages

Signed-off-by: Ron Isaacson <isaacson.ron@gmail.com>
This commit is contained in:
Ron Isaacson 2021-01-02 14:59:57 -05:00 committed by GitHub
parent d133959abf
commit 353f7af076
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 290 additions and 307 deletions

View File

@ -134,7 +134,7 @@ public class PowermaxBridgeHandler extends BaseBridgeHandler implements Powermax
// Delay the startup in case the handler is restarted immediately
globalJob = scheduler.scheduleWithFixedDelay(() -> {
try {
logger.debug("Powermax job...");
logger.trace("Powermax job...");
updateMotionSensorState();
if (isConnected()) {
checkKeepAlive();

View File

@ -32,9 +32,7 @@ public class PowermaxAckMessage extends PowermaxBaseMessage {
}
@Override
public PowermaxState handleMessage(PowermaxCommManager commManager) {
super.handleMessage(commManager);
protected PowermaxState handleMessageInternal(PowermaxCommManager commManager) {
if (commManager == null) {
return null;
}

View File

@ -12,6 +12,7 @@
*/
package org.openhab.binding.powermax.internal.message;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.powermax.internal.state.PowermaxState;
import org.openhab.core.util.HexUtils;
import org.slf4j.Logger;
@ -30,6 +31,7 @@ public class PowermaxBaseMessage {
private int code;
private PowermaxSendType sendType;
private PowermaxReceiveType receiveType;
private Object messageType;
/**
* Constructor.
@ -38,6 +40,7 @@ public class PowermaxBaseMessage {
*/
public PowermaxBaseMessage(byte[] message) {
this.sendType = null;
this.messageType = "UNKNOWN";
decodeMessage(message);
}
@ -58,6 +61,7 @@ public class PowermaxBaseMessage {
*/
public PowermaxBaseMessage(PowermaxSendType sendType, byte[] param) {
this.sendType = sendType;
this.messageType = "UNKNOWN";
byte[] message = new byte[sendType.getMessage().length + 3];
int index = 0;
message[index++] = 0x0D;
@ -87,6 +91,8 @@ public class PowermaxBaseMessage {
} catch (IllegalArgumentException e) {
receiveType = null;
}
messageType = sendType != null ? sendType : receiveType != null ? receiveType : "UNKNOWN";
}
/**
@ -94,17 +100,26 @@ public class PowermaxBaseMessage {
*
* @return a new state containing all changes driven by the message
*/
public PowermaxState handleMessage(PowermaxCommManager commManager) {
public final PowermaxState handleMessage(PowermaxCommManager commManager) {
// Send an ACK if needed
if (isAckRequired() && commManager != null) {
commManager.sendAck(this, (byte) 0x02);
}
if (logger.isDebugEnabled()) {
logger.debug("{}message handled by class {}: {}", (receiveType == null) ? "Unsupported " : "",
this.getClass().getSimpleName(), this);
logger.debug("{}message will be handled by class {}:", (receiveType == null) ? "Unsupported " : "",
this.getClass().getSimpleName());
debug("Raw data", rawData);
debug("Message type", code, messageType.toString());
}
PowermaxState newState = handleMessageInternal(commManager);
return newState;
}
protected PowermaxState handleMessageInternal(PowermaxCommManager commManager) {
return null;
}
@ -147,17 +162,42 @@ public class PowermaxBaseMessage {
return receiveType == null || receiveType.isAckRequired();
}
@Override
public String toString() {
String str = "\n - Raw data = " + HexUtils.bytesToHex(rawData);
str += "\n - type = " + String.format("%02X", code);
if (sendType != null) {
str += " ( " + sendType.toString() + " )";
} else if (receiveType != null) {
str += " ( " + receiveType.toString() + " )";
// Debugging helpers
public void debug(String name, String info, @Nullable String decoded) {
if (!logger.isDebugEnabled()) {
return;
}
return str;
String decodedStr = "";
if (decoded != null && !decoded.isBlank()) {
decodedStr = " - " + decoded;
}
logger.debug("| {} = {}{}", name, info, decodedStr);
}
public void debug(String name, String info) {
debug(name, info, null);
}
public void debug(String name, byte[] data, @Nullable String decoded) {
String hex = "0x" + HexUtils.bytesToHex(data);
debug(name, hex, decoded);
}
public void debug(String name, byte[] data) {
debug(name, data, null);
}
public void debug(String name, int data, @Nullable String decoded) {
String hex = String.format("0x%02X", data);
debug(name, hex, decoded);
}
public void debug(String name, int data) {
debug(name, data, null);
}
/**

View File

@ -239,7 +239,8 @@ public class PowermaxCommManager implements PowermaxMessageEventListener {
PowermaxBaseMessage message = messageEvent.getMessage();
if (logger.isDebugEnabled()) {
logger.debug("onNewMessageReceived(): received message {}",
logger.debug("onNewMessageReceived(): received message 0x{} ({})",
HexUtils.bytesToHex(message.getRawData()),
(message.getReceiveType() != null) ? message.getReceiveType()
: String.format("%02X", message.getCode()));
}

View File

@ -36,9 +36,7 @@ public class PowermaxDeniedMessage extends PowermaxBaseMessage {
}
@Override
public PowermaxState handleMessage(PowermaxCommManager commManager) {
super.handleMessage(commManager);
protected PowermaxState handleMessageInternal(PowermaxCommManager commManager) {
if (commManager == null) {
return null;
}

View File

@ -32,9 +32,7 @@ public class PowermaxDownloadRetryMessage extends PowermaxBaseMessage {
}
@Override
public PowermaxState handleMessage(PowermaxCommManager commManager) {
super.handleMessage(commManager);
protected PowermaxState handleMessageInternal(PowermaxCommManager commManager) {
if (commManager == null) {
return null;
}
@ -42,20 +40,10 @@ public class PowermaxDownloadRetryMessage extends PowermaxBaseMessage {
byte[] message = getRawData();
int waitTime = message[4] & 0x000000FF;
debug("Wait time", waitTime + " seconds");
commManager.sendMessageLater(PowermaxSendType.DOWNLOAD, waitTime);
return null;
}
@Override
public String toString() {
String str = super.toString();
byte[] message = getRawData();
int waitTime = message[4] & 0x000000FF;
str += "\n - wait time = " + waitTime + " seconds";
return str;
}
}

View File

@ -22,44 +22,6 @@ import org.openhab.binding.powermax.internal.state.PowermaxState;
*/
public class PowermaxEventLogMessage extends PowermaxBaseMessage {
public static final String[] LOG_EVENT_TABLE = new String[] { "None", "Interior Alarm", "Perimeter Alarm",
"Delay Alarm", "24h Silent Alarm", "24h Audible Alarm", "Tamper", "Control Panel Tamper", "Tamper Alarm",
"Tamper Alarm", "Communication Loss", "Panic From Keyfob", "Panic From Control Panel", "Duress",
"Confirm Alarm", "General Trouble", "General Trouble Restore", "Interior Restore", "Perimeter Restore",
"Delay Restore", "24h Silent Restore", "24h Audible Restore", "Tamper Restore",
"Control Panel Tamper Restore", "Tamper Restore", "Tamper Restore", "Communication Restore", "Cancel Alarm",
"General Restore", "Trouble Restore", "Not used", "Recent Close", "Fire", "Fire Restore", "No Active",
"Emergency", "No used", "Disarm Latchkey", "Panic Restore", "Supervision (Inactive)",
"Supervision Restore (Active)", "Low Battery", "Low Battery Restore", "AC Fail", "AC Restore",
"Control Panel Low Battery", "Control Panel Low Battery Restore", "RF Jamming", "RF Jamming Restore",
"Communications Failure", "Communications Restore", "Telephone Line Failure", "Telephone Line Restore",
"Auto Test", "Fuse Failure", "Fuse Restore", "Keyfob Low Battery", "Keyfob Low Battery Restore",
"Engineer Reset", "Battery Disconnect", "1-Way Keypad Low Battery", "1-Way Keypad Low Battery Restore",
"1-Way Keypad Inactive", "1-Way Keypad Restore Active", "Low Battery", "Clean Me", "Fire Trouble",
"Low Battery", "Battery Restore", "AC Fail", "AC Restore", "Supervision (Inactive)",
"Supervision Restore (Active)", "Gas Alert", "Gas Alert Restore", "Gas Trouble", "Gas Trouble Restore",
"Flood Alert", "Flood Alert Restore", "X-10 Trouble", "X-10 Trouble Restore", "Arm Home", "Arm Away",
"Quick Arm Home", "Quick Arm Away", "Disarm", "Fail To Auto-Arm", "Enter To Test Mode",
"Exit From Test Mode", "Force Arm", "Auto Arm", "Instant Arm", "Bypass", "Fail To Arm", "Door Open",
"Communication Established By Control Panel", "System Reset", "Installer Programming", "Wrong Password",
"Not Sys Event", "Not Sys Event", "Extreme Hot Alert", "Extreme Hot Alert Restore", "Freeze Alert",
"Freeze Alert Restore", "Human Cold Alert", "Human Cold Alert Restore", "Human Hot Alert",
"Human Hot Alert Restore", "Temperature Sensor Trouble", "Temperature Sensor Trouble Restore",
// new values partition models
"PIR Mask", "PIR Mask Restore", "", "", "", "", "", "", "", "", "", "", "Alarmed", "Restore", "Alarmed",
"Restore", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "Exit Installer", "Enter Installer",
"", "", "", "", "" };
public static final String[] LOG_USER_TABLE = new String[] { "System", "Zone 1", "Zone 2", "Zone 3", "Zone 4",
"Zone 5", "Zone 6", "Zone 7", "Zone 8", "Zone 9", "Zone 10", "Zone 11", "Zone 12", "Zone 13", "Zone 14",
"Zone 15", "Zone 16", "Zone 17", "Zone 18", "Zone 19", "Zone 20", "Zone 21", "Zone 22", "Zone 23",
"Zone 24", "Zone 25", "Zone 26", "Zone 27", "Zone 28", "Zone 29", "Zone 30", "Fob 1", "Fob 2", "Fob 3",
"Fob 4", "Fob 5", "Fob 6", "Fob 7", "Fob 8", "User 1", "User 2", "User 3", "User 4", "User 5", "User 6",
"User 7", "User 8", "Pad 1", "Pad 2", "Pad 3", "Pad 4", "Pad 5", "Pad 6", "Pad 7", "Pad 8", "Siren 1",
"Siren 2", "2Pad 1", "2Pad 2", "2Pad 3", "2Pad 4", "X10 1", "X10 2", "X10 3", "X10 4", "X10 5", "X10 6",
"X10 7", "X10 8", "X10 9", "X10 10", "X10 11", "X10 12", "X10 13", "X10 14", "X10 15", "PGM", "GSM",
"P-LINK", "PTag 1", "PTag 2", "PTag 3", "PTag 4", "PTag 5", "PTag 6", "PTag 7", "PTag 8" };
/**
* Constructor
*
@ -71,9 +33,7 @@ public class PowermaxEventLogMessage extends PowermaxBaseMessage {
}
@Override
public PowermaxState handleMessage(PowermaxCommManager commManager) {
super.handleMessage(commManager);
protected PowermaxState handleMessageInternal(PowermaxCommManager commManager) {
if (commManager == null) {
return null;
}
@ -83,11 +43,14 @@ public class PowermaxEventLogMessage extends PowermaxBaseMessage {
byte[] message = getRawData();
int eventNum = message[3] & 0x000000FF;
eventNum--;
if (eventNum == 0) {
debug("Event number", eventNum);
if (eventNum == 1) {
int eventCnt = message[2] & 0x000000FF;
updatedState.setEventLogSize(eventCnt - 1);
debug("Event count", eventCnt);
} else {
int second = message[4] & 0x000000FF;
int minute = message[5] & 0x000000FF;
@ -95,14 +58,11 @@ public class PowermaxEventLogMessage extends PowermaxBaseMessage {
int day = message[7] & 0x000000FF;
int month = message[8] & 0x000000FF;
int year = (message[9] & 0x000000FF) + 2000;
String timestamp = String.format("%02d/%02d/%04d %02d:%02d:%02d", day, month, year, hour, minute, second);
byte eventZone = message[10];
byte logEvent = message[11];
String logEventStr = ((logEvent & 0x000000FF) < LOG_EVENT_TABLE.length)
? LOG_EVENT_TABLE[logEvent & 0x000000FF]
: "UNKNOWN";
String logUserStr = ((eventZone & 0x000000FF) < LOG_USER_TABLE.length)
? LOG_USER_TABLE[eventZone & 0x000000FF]
: "UNKNOWN";
String logEventStr = PowermaxMessageConstants.getSystemEventString(logEvent & 0x000000FF);
String logUserStr = PowermaxMessageConstants.getZoneOrUserString(eventZone & 0x000000FF);
String eventStr;
if (panelSettings.getPanelType().getPartitions() > 1) {
@ -116,55 +76,18 @@ public class PowermaxEventLogMessage extends PowermaxBaseMessage {
} else {
part = "Panel";
}
eventStr = String.format("%02d/%02d/%04d %02d:%02d / %s: %s (%s)", day, month, year, hour, minute, part,
logEventStr, logUserStr);
eventStr = String.format("%s / %s: %s (%s)", timestamp, part, logEventStr, logUserStr);
} else {
eventStr = String.format("%02d/%02d/%04d %02d:%02d:%02d: %s (%s)", day, month, year, hour, minute,
second, logEventStr, logUserStr);
eventStr = String.format("%s: %s (%s)", timestamp, logEventStr, logUserStr);
}
updatedState.setEventLogSize(eventNum);
updatedState.setEventLog(eventNum, eventStr);
updatedState.setEventLogSize(eventNum - 1);
updatedState.setEventLog(eventNum - 1, eventStr);
debug("Event " + eventNum + " date/time", timestamp);
debug("Event " + eventNum + " zone code", eventZone, logUserStr);
debug("Event " + eventNum + " event code", logEvent, logEventStr);
}
return updatedState;
}
@Override
public String toString() {
String str = super.toString();
byte[] message = getRawData();
int eventNum = message[3] & 0x000000FF;
str += "\n - event number = " + eventNum;
if (eventNum == 1) {
int eventCnt = message[2] & 0x000000FF;
str += "\n - event count = " + eventCnt;
} else {
int second = message[4] & 0x000000FF;
int minute = message[5] & 0x000000FF;
int hour = message[6] & 0x000000FF;
int day = message[7] & 0x000000FF;
int month = message[8] & 0x000000FF;
int year = (message[9] & 0x000000FF) + 2000;
byte eventZone = message[10];
byte logEvent = message[11];
String logEventStr = ((logEvent & 0x000000FF) < LOG_EVENT_TABLE.length)
? LOG_EVENT_TABLE[logEvent & 0x000000FF]
: "UNKNOWN";
String logUserStr = ((eventZone & 0x000000FF) < LOG_USER_TABLE.length)
? LOG_USER_TABLE[eventZone & 0x000000FF]
: "UNKNOWN";
str += "\n - event " + eventNum + " date & time = "
+ String.format("%02d/%02d/%04d %02d:%02d:%02d", day, month, year, hour, minute, second);
str += "\n - event " + eventNum + " zone code = " + String.format("%08X - %s", eventZone, logUserStr);
str += "\n - event " + eventNum + " event code = " + String.format("%08X - %s", logEvent, logEventStr);
}
return str;
}
}

View File

@ -37,9 +37,7 @@ public class PowermaxInfoMessage extends PowermaxBaseMessage {
}
@Override
public PowermaxState handleMessage(PowermaxCommManager commManager) {
super.handleMessage(commManager);
protected PowermaxState handleMessageInternal(PowermaxCommManager commManager) {
if (commManager == null) {
return null;
}
@ -47,15 +45,20 @@ public class PowermaxInfoMessage extends PowermaxBaseMessage {
PowermaxState updatedState = commManager.createNewState();
byte[] message = getRawData();
byte panelTypeNr = message[7];
String panelTypeStr;
PowermaxPanelType panelType = null;
try {
panelType = PowermaxPanelType.fromCode(message[7]);
panelType = PowermaxPanelType.fromCode(panelTypeNr);
panelTypeStr = panelType.toString();
} catch (IllegalArgumentException e) {
logger.debug("Powermax alarm binding: unknwon panel type for code {}", message[7] & 0x000000FF);
panelType = null;
panelTypeStr = "UNKNOWN";
}
debug("Panel type", panelTypeNr, panelTypeStr);
logger.debug("Reading panel settings");
updatedState.setDownloadMode(true);
commManager.sendMessage(PowermaxSendType.DL_PANELFW);
@ -70,16 +73,4 @@ public class PowermaxInfoMessage extends PowermaxBaseMessage {
return updatedState;
}
@Override
public String toString() {
String str = super.toString();
byte[] message = getRawData();
byte panelTypeNr = message[7];
str += "\n - panel type number = " + String.format("%02X", panelTypeNr);
return str;
}
}

View File

@ -0,0 +1,102 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.powermax.internal.message;
/**
* Constants used in Powermax messages
*
* @author Ron Isaacson - Initial contribution
*/
public class PowermaxMessageConstants {
private PowermaxMessageConstants() {
}
private static String getValue(String[] table, int index) {
return (((index >= 0) && (index < table.length)) ? table[index] : "UNKNOWN");
}
/**
* System event lookup
*/
public static String getSystemEventString(int code) {
return getValue(SYSTEM_EVENT_TABLE, code);
}
private static final String[] SYSTEM_EVENT_TABLE = new String[] { "None", "Interior Alarm", "Perimeter Alarm",
"Delay Alarm", "24h Silent Alarm", "24h Audible Alarm", "Tamper", "Control Panel Tamper", "Tamper Alarm",
"Tamper Alarm", "Communication Loss", "Panic From Keyfob", "Panic From Control Panel", "Duress",
"Confirm Alarm", "General Trouble", "General Trouble Restore", "Interior Restore", "Perimeter Restore",
"Delay Restore", "24h Silent Restore", "24h Audible Restore", "Tamper Restore",
"Control Panel Tamper Restore", "Tamper Restore", "Tamper Restore", "Communication Restore", "Cancel Alarm",
"General Restore", "Trouble Restore", "Not used", "Recent Close", "Fire", "Fire Restore", "No Active",
"Emergency", "No used", "Disarm Latchkey", "Panic Restore", "Supervision (Inactive)",
"Supervision Restore (Active)", "Low Battery", "Low Battery Restore", "AC Fail", "AC Restore",
"Control Panel Low Battery", "Control Panel Low Battery Restore", "RF Jamming", "RF Jamming Restore",
"Communications Failure", "Communications Restore", "Telephone Line Failure", "Telephone Line Restore",
"Auto Test", "Fuse Failure", "Fuse Restore", "Keyfob Low Battery", "Keyfob Low Battery Restore",
"Engineer Reset", "Battery Disconnect", "1-Way Keypad Low Battery", "1-Way Keypad Low Battery Restore",
"1-Way Keypad Inactive", "1-Way Keypad Restore Active", "Low Battery", "Clean Me", "Fire Trouble",
"Low Battery", "Battery Restore", "AC Fail", "AC Restore", "Supervision (Inactive)",
"Supervision Restore (Active)", "Gas Alert", "Gas Alert Restore", "Gas Trouble", "Gas Trouble Restore",
"Flood Alert", "Flood Alert Restore", "X-10 Trouble", "X-10 Trouble Restore", "Arm Home", "Arm Away",
"Quick Arm Home", "Quick Arm Away", "Disarm", "Fail To Auto-Arm", "Enter To Test Mode",
"Exit From Test Mode", "Force Arm", "Auto Arm", "Instant Arm", "Bypass", "Fail To Arm", "Door Open",
"Communication Established By Control Panel", "System Reset", "Installer Programming", "Wrong Password",
"Not Sys Event", "Not Sys Event", "Extreme Hot Alert", "Extreme Hot Alert Restore", "Freeze Alert",
"Freeze Alert Restore", "Human Cold Alert", "Human Cold Alert Restore", "Human Hot Alert",
"Human Hot Alert Restore", "Temperature Sensor Trouble", "Temperature Sensor Trouble Restore",
// new values partition models
"PIR Mask", "PIR Mask Restore", "", "", "", "", "", "", "", "", "", "", "Alarmed", "Restore", "Alarmed",
"Restore", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "Exit Installer", "Enter Installer",
"", "", "", "", "" };
/**
* Zone/User lookup
*/
public static String getZoneOrUserString(int code) {
return getValue(ZONE_OR_USER_TABLE, code);
}
private static final String[] ZONE_OR_USER_TABLE = new String[] { "System", "Zone 1", "Zone 2", "Zone 3", "Zone 4",
"Zone 5", "Zone 6", "Zone 7", "Zone 8", "Zone 9", "Zone 10", "Zone 11", "Zone 12", "Zone 13", "Zone 14",
"Zone 15", "Zone 16", "Zone 17", "Zone 18", "Zone 19", "Zone 20", "Zone 21", "Zone 22", "Zone 23",
"Zone 24", "Zone 25", "Zone 26", "Zone 27", "Zone 28", "Zone 29", "Zone 30", "Fob 1", "Fob 2", "Fob 3",
"Fob 4", "Fob 5", "Fob 6", "Fob 7", "Fob 8", "User 1", "User 2", "User 3", "User 4", "User 5", "User 6",
"User 7", "User 8", "Pad 1", "Pad 2", "Pad 3", "Pad 4", "Pad 5", "Pad 6", "Pad 7", "Pad 8", "Siren 1",
"Siren 2", "2Pad 1", "2Pad 2", "2Pad 3", "2Pad 4", "X10 1", "X10 2", "X10 3", "X10 4", "X10 5", "X10 6",
"X10 7", "X10 8", "X10 9", "X10 10", "X10 11", "X10 12", "X10 13", "X10 14", "X10 15", "PGM", "GSM",
"P-LINK", "PTag 1", "PTag 2", "PTag 3", "PTag 4", "PTag 5", "PTag 6", "PTag 7", "PTag 8" };
/**
* Zone event lookup
*/
public static String getZoneEventString(int code) {
return getValue(ZONE_EVENT_TABLE, code);
}
private static final String[] ZONE_EVENT_TABLE = new String[] { "None", "Tamper Alarm", "Tamper Restore", "Open",
"Closed", "Violated (Motion)", "Panic Alarm", "RF Jamming", "Tamper Open", "Communication Failure",
"Line Failure", "Fuse", "Not Active", "Low Battery", "AC Failure", "Fire Alarm", "Emergency",
"Siren Tamper", "Siren Tamper Restore", "Siren Low Battery", "Siren AC Fail" };
/**
* Message type lookup
*/
public static String getMessageTypeString(int code) {
return getValue(MESSAGE_TYPE_TABLE, code);
}
private static final String[] MESSAGE_TYPE_TABLE = new String[] { "None", "Log Message", "Status Message",
"Tamper Message", "Zone Message", "Unknown", "Enroll/Bypass Message" };
}

View File

@ -32,9 +32,7 @@ public class PowermaxPanelMessage extends PowermaxBaseMessage {
}
@Override
public PowermaxState handleMessage(PowermaxCommManager commManager) {
super.handleMessage(commManager);
protected PowermaxState handleMessageInternal(PowermaxCommManager commManager) {
if (commManager == null) {
return null;
}
@ -44,18 +42,19 @@ public class PowermaxPanelMessage extends PowermaxBaseMessage {
byte[] message = getRawData();
int msgCnt = message[2] & 0x000000FF;
debug("Event count", msgCnt);
for (int i = 1; i <= msgCnt; i++) {
byte eventZone = message[2 + 2 * i];
byte logEvent = message[3 + 2 * i];
int eventType = logEvent & 0x0000007F;
String logEventStr = (eventType < PowermaxEventLogMessage.LOG_EVENT_TABLE.length)
? PowermaxEventLogMessage.LOG_EVENT_TABLE[eventType]
: "UNKNOWN";
String logUserStr = ((eventZone & 0x000000FF) < PowermaxEventLogMessage.LOG_USER_TABLE.length)
? PowermaxEventLogMessage.LOG_USER_TABLE[eventZone & 0x000000FF]
: "UNKNOWN";
String logEventStr = PowermaxMessageConstants.getSystemEventString(eventType);
String logUserStr = PowermaxMessageConstants.getZoneOrUserString(eventZone & 0x000000FF);
updatedState.setPanelStatus(logEventStr + " (" + logUserStr + ")");
debug("Event " + i + " zone code", eventZone, logUserStr);
debug("Event " + i + " event code", eventType, logEventStr);
String alarmStatus;
try {
PowermaxAlarmType alarmType = PowermaxAlarmType.fromCode(eventType);
@ -82,23 +81,4 @@ public class PowermaxPanelMessage extends PowermaxBaseMessage {
return updatedState;
}
@Override
public String toString() {
String str = super.toString();
byte[] message = getRawData();
int msgCnt = message[2] & 0x000000FF;
str += "\n - event count = " + msgCnt;
for (int i = 1; i <= msgCnt; i++) {
byte eventZone = message[2 + 2 * i];
byte logEvent = message[3 + 2 * i];
str += "\n - event " + i + " zone code = " + String.format("%08X", eventZone);
str += "\n - event " + i + " event code = " + String.format("%08X", logEvent);
}
return str;
}
}

View File

@ -32,9 +32,7 @@ public class PowermaxPowerMasterMessage extends PowermaxBaseMessage {
}
@Override
public PowermaxState handleMessage(PowermaxCommManager commManager) {
super.handleMessage(commManager);
protected PowermaxState handleMessageInternal(PowermaxCommManager commManager) {
if (commManager == null) {
return null;
}
@ -42,6 +40,11 @@ public class PowermaxPowerMasterMessage extends PowermaxBaseMessage {
byte[] message = getRawData();
byte msgType = message[2];
byte subType = message[3];
byte msgLen = message[4];
debug("Type", msgType);
debug("Subtype", subType);
debug("Message length", msgLen);
if ((msgType == 0x03) && (subType == 0x39)) {
commManager.sendMessage(PowermaxSendType.POWERMASTER_ZONE_STAT1);
@ -50,20 +53,4 @@ public class PowermaxPowerMasterMessage extends PowermaxBaseMessage {
return null;
}
@Override
public String toString() {
String str = super.toString();
byte[] message = getRawData();
byte msgType = message[2];
byte subType = message[3];
byte msgLen = message[4];
str += "\n - type = " + String.format("%02X", msgType);
str += "\n - subtype = " + String.format("%02X", subType);
str += "\n - msgLen = " + String.format("%02X", msgLen);
return str;
}
}

View File

@ -36,9 +36,7 @@ public class PowermaxPowerlinkMessage extends PowermaxBaseMessage {
}
@Override
public PowermaxState handleMessage(PowermaxCommManager commManager) {
super.handleMessage(commManager);
protected PowermaxState handleMessageInternal(PowermaxCommManager commManager) {
if (commManager == null) {
return null;
}
@ -50,37 +48,31 @@ public class PowermaxPowerlinkMessage extends PowermaxBaseMessage {
if (subType == 0x03) {
// keep alive message
debug("Subtype", subType, "Keep Alive");
commManager.sendAck(this, (byte) 0x02);
updatedState = commManager.createNewState();
updatedState.setLastKeepAlive(System.currentTimeMillis());
} else if (subType == 0x0A && message[4] == 0x01) {
logger.debug("Powermax alarm binding: Enrolling Powerlink");
commManager.enrollPowerlink();
updatedState = commManager.createNewState();
updatedState.setDownloadSetupRequired(true);
} else if (subType == 0x0A) {
byte enroll = message[4];
debug("Subtype", subType, "Enroll");
debug("Enroll", enroll);
if (enroll == 0x01) {
logger.debug("Powermax alarm binding: Enrolling Powerlink");
commManager.enrollPowerlink();
updatedState = commManager.createNewState();
updatedState.setDownloadSetupRequired(true);
} else {
commManager.sendAck(this, (byte) 0x02);
}
} else {
debug("Subtype", subType, "UNKNOWN");
commManager.sendAck(this, (byte) 0x02);
}
return updatedState;
}
@Override
public String toString() {
String str = super.toString();
byte[] message = getRawData();
byte subType = message[2];
if (subType == 0x03) {
str += "\n - sub type = keep alive";
} else if (subType == 0x0A) {
str += "\n - sub type = enroll";
str += "\n - enroll = " + String.format("%02X", message[4]);
} else {
str += "\n - sub type = " + String.format("%02X", subType);
}
return str;
}
}

View File

@ -38,9 +38,7 @@ public class PowermaxSettingsMessage extends PowermaxBaseMessage {
}
@Override
public PowermaxState handleMessage(PowermaxCommManager commManager) {
super.handleMessage(commManager);
protected PowermaxState handleMessageInternal(PowermaxCommManager commManager) {
if (commManager == null) {
return null;
}
@ -52,6 +50,9 @@ public class PowermaxSettingsMessage extends PowermaxBaseMessage {
int page = message[3] & 0x000000FF;
int length = 0;
debug("Page", page, Integer.toString(page));
debug("Index", index, Integer.toString(index));
if (getReceiveType() == PowermaxReceiveType.SETTINGS) {
length = message.length - 6;
updatedState.setUpdateSettings(Arrays.copyOfRange(message, 2, 2 + 2 + length));
@ -74,18 +75,4 @@ public class PowermaxSettingsMessage extends PowermaxBaseMessage {
return updatedState;
}
@Override
public String toString() {
String str = super.toString();
byte[] message = getRawData();
int index = message[2] & 0x000000FF;
int page = message[3] & 0x000000FF;
str += "\n - page = " + String.format("%02X (%d)", page, page);
str += "\n - index = " + String.format("%02X (%d)", index, index);
return str;
}
}

View File

@ -12,6 +12,10 @@
*/
package org.openhab.binding.powermax.internal.message;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import org.openhab.binding.powermax.internal.state.PowermaxArmMode;
import org.openhab.binding.powermax.internal.state.PowermaxPanelSettings;
import org.openhab.binding.powermax.internal.state.PowermaxState;
@ -24,10 +28,34 @@ import org.openhab.binding.powermax.internal.state.PowermaxZoneSettings;
*/
public class PowermaxStatusMessage extends PowermaxBaseMessage {
private static final String[] EVENT_TYPE_TABLE = new String[] { "None", "Tamper Alarm", "Tamper Restore", "Open",
"Closed", "Violated (Motion)", "Panic Alarm", "RF Jamming", "Tamper Open", "Communication Failure",
"Line Failure", "Fuse", "Not Active", "Low Battery", "AC Failure", "Fire Alarm", "Emergency",
"Siren Tamper", "Siren Tamper Restore", "Siren Low Battery", "Siren AC Fail" };
private static byte[] zoneBytes(byte zones1, byte zones9, byte zones17, byte zones25) {
return new byte[] { zones25, zones17, zones9, zones1 };
}
private static boolean[] zoneBits(byte[] zoneBytes) {
boolean[] zones = new boolean[32];
char[] binary = new BigInteger(zoneBytes).toString(2).toCharArray();
int len = binary.length - 1;
for (int i = len; i >= 0; i--) {
zones[len - i + 1] = (binary[i] == '1');
}
return zones;
}
private static String zoneList(byte[] zoneBytes) {
boolean[] zones = zoneBits(zoneBytes);
List<String> names = new ArrayList<>();
for (int i = 1; i < zones.length; i++) {
if (zones[i]) {
names.add(String.format("Zone %d", i));
}
}
return String.join(", ", names);
}
/**
* Constructor
@ -40,9 +68,7 @@ public class PowermaxStatusMessage extends PowermaxBaseMessage {
}
@Override
public PowermaxState handleMessage(PowermaxCommManager commManager) {
super.handleMessage(commManager);
protected PowermaxState handleMessageInternal(PowermaxCommManager commManager) {
if (commManager == null) {
return null;
}
@ -52,17 +78,27 @@ public class PowermaxStatusMessage extends PowermaxBaseMessage {
byte[] message = getRawData();
byte eventType = message[3];
String eventTypeStr = PowermaxMessageConstants.getMessageTypeString(eventType & 0x000000FF);
debug("Event type", eventType, eventTypeStr);
if (eventType == 0x02) {
int zoneStatus = (message[4] & 0x000000FF) | ((message[5] << 8) & 0x0000FF00)
| ((message[6] << 16) & 0x00FF0000) | ((message[7] << 24) & 0xFF000000);
int batteryStatus = (message[8] & 0x000000FF) | ((message[9] << 8) & 0x0000FF00)
| ((message[10] << 16) & 0x00FF0000) | ((message[11] << 24) & 0xFF000000);
byte[] zoneStatusBytes = zoneBytes(message[4], message[5], message[6], message[7]);
byte[] batteryStatusBytes = zoneBytes(message[8], message[9], message[10], message[11]);
boolean[] zoneStatus = zoneBits(zoneStatusBytes);
boolean[] batteryStatus = zoneBits(batteryStatusBytes);
String zoneStatusStr = zoneList(zoneStatusBytes);
String batteryStatusStr = zoneList(batteryStatusBytes);
for (int i = 1; i <= panelSettings.getNbZones(); i++) {
updatedState.setSensorTripped(i, ((zoneStatus >> (i - 1)) & 0x1) > 0);
updatedState.setSensorLowBattery(i, ((batteryStatus >> (i - 1)) & 0x1) > 0);
updatedState.setSensorTripped(i, zoneStatus[i]);
updatedState.setSensorLowBattery(i, batteryStatus[i]);
}
debug("Zone status", zoneStatusBytes, zoneStatusStr);
debug("Battery status", batteryStatusBytes, batteryStatusStr);
} else if (eventType == 0x04) {
byte sysStatus = message[4];
byte sysFlags = message[5];
@ -70,9 +106,8 @@ public class PowermaxStatusMessage extends PowermaxBaseMessage {
byte zoneEType = message[7];
int x10Status = (message[10] & 0x000000FF) | ((message[11] << 8) & 0x0000FF00);
String zoneETypeStr = ((zoneEType & 0x000000FF) < EVENT_TYPE_TABLE.length)
? EVENT_TYPE_TABLE[zoneEType & 0x000000FF]
: "UNKNOWN";
String eventZoneStr = PowermaxMessageConstants.getZoneOrUserString(eventZone & 0x000000FF);
String zoneETypeStr = PowermaxMessageConstants.getZoneEventString(zoneEType & 0x000000FF);
if (zoneEType == 0x03) {
updatedState.setSensorTripped(eventZone, Boolean.TRUE);
@ -155,6 +190,12 @@ public class PowermaxStatusMessage extends PowermaxBaseMessage {
updatedState.setArmMode(statusStr);
updatedState.setStatusStr(statusStr + ", " + sysStatusStr);
debug("System status", sysStatus, statusStr);
debug("System flags", sysFlags, sysStatusStr);
debug("Event zone", eventZone, eventZoneStr);
debug("Zone event type", zoneEType, zoneETypeStr);
debug("X10 status", x10Status);
for (int i = 1; i <= panelSettings.getNbZones(); i++) {
PowermaxZoneSettings zone = panelSettings.getZoneSettings(i);
if (zone != null) {
@ -171,56 +212,17 @@ public class PowermaxStatusMessage extends PowermaxBaseMessage {
}
}
} else if (eventType == 0x06) {
int zoneBypass = (message[8] & 0x000000FF) | ((message[9] << 8) & 0x0000FF00)
| ((message[10] << 16) & 0x00FF0000) | ((message[11] << 24) & 0xFF000000);
byte[] zoneBypassBytes = zoneBytes(message[8], message[9], message[10], message[11]);
boolean[] zoneBypass = zoneBits(zoneBypassBytes);
String zoneBypassStr = zoneList(zoneBypassBytes);
for (int i = 1; i <= panelSettings.getNbZones(); i++) {
updatedState.setSensorBypassed(i, ((zoneBypass >> (i - 1)) & 0x1) > 0);
updatedState.setSensorBypassed(i, zoneBypass[i]);
}
debug("Zone bypass", zoneBypassBytes, zoneBypassStr);
}
return updatedState;
}
@Override
public String toString() {
String str = super.toString();
byte[] message = getRawData();
byte eventType = message[3];
str += "\n - event type = " + String.format("%02X", eventType);
if (eventType == 0x02) {
int zoneStatus = (message[4] & 0x000000FF) | ((message[5] << 8) & 0x0000FF00)
| ((message[6] << 16) & 0x00FF0000) | ((message[7] << 24) & 0xFF000000);
int batteryStatus = (message[8] & 0x000000FF) | ((message[9] << 8) & 0x0000FF00)
| ((message[10] << 16) & 0x00FF0000) | ((message[11] << 24) & 0xFF000000);
str += "\n - zone status = " + String.format("%08X", zoneStatus);
str += "\n - battery status = " + String.format("%08X", batteryStatus);
} else if (eventType == 0x04) {
byte sysStatus = message[4];
byte sysFlags = message[5];
byte eventZone = message[6];
byte zoneEType = message[7];
int x10Status = (message[10] & 0x000000FF) | ((message[11] << 8) & 0x0000FF00);
String zoneETypeStr = ((zoneEType & 0x000000FF) < EVENT_TYPE_TABLE.length)
? EVENT_TYPE_TABLE[zoneEType & 0x000000FF]
: "UNKNOWN";
str += "\n - system status = " + String.format("%02X", sysStatus);
str += "\n - system flags = " + String.format("%02X", sysFlags);
str += "\n - event zone = " + eventZone;
str += String.format("\n - zone event type = %02X (%s)", zoneEType, zoneETypeStr);
str += "\n - X10 status = " + String.format("%04X", x10Status);
} else if (eventType == 0x06) {
int zoneBypass = (message[8] & 0x000000FF) | ((message[9] << 8) & 0x0000FF00)
| ((message[10] << 16) & 0x00FF0000) | ((message[11] << 24) & 0xFF000000);
str += "\n - zone bypass = " + String.format("%08X", zoneBypass);
}
return str;
}
}

View File

@ -32,9 +32,7 @@ public class PowermaxTimeoutMessage extends PowermaxBaseMessage {
}
@Override
public PowermaxState handleMessage(PowermaxCommManager commManager) {
super.handleMessage(commManager);
protected PowermaxState handleMessageInternal(PowermaxCommManager commManager) {
if (commManager != null) {
commManager.sendMessage(PowermaxSendType.EXIT);
}

View File

@ -32,9 +32,7 @@ public class PowermaxZonesNameMessage extends PowermaxBaseMessage {
}
@Override
public PowermaxState handleMessage(PowermaxCommManager commManager) {
super.handleMessage(commManager);
protected PowermaxState handleMessageInternal(PowermaxCommManager commManager) {
if (commManager == null) {
return null;
}

View File

@ -32,9 +32,7 @@ public class PowermaxZonesTypeMessage extends PowermaxBaseMessage {
}
@Override
public PowermaxState handleMessage(PowermaxCommManager commManager) {
super.handleMessage(commManager);
protected PowermaxState handleMessageInternal(PowermaxCommManager commManager) {
if (commManager == null) {
return null;
}