use of org.openhab.binding.zwave.internal.protocol.commandclass.ZWaveCommandClass in project openhab1-addons by openhab.
the class ApplicationUpdateMessageClass method handleRequest.
@Override
public boolean handleRequest(ZWaveController zController, SerialMessage lastSentMessage, SerialMessage incomingMessage) {
int nodeId;
boolean result = true;
UpdateState updateState = UpdateState.getUpdateState(incomingMessage.getMessagePayloadByte(0));
switch(updateState) {
case NODE_INFO_RECEIVED:
// We've received a NIF, and this contains the node ID.
nodeId = incomingMessage.getMessagePayloadByte(1);
logger.debug("NODE {}: Application update request. Node information received.", nodeId);
int length = incomingMessage.getMessagePayloadByte(2);
ZWaveNode node = zController.getNode(nodeId);
if (node == null) {
logger.debug("NODE {}: Application update request. Node not known!", nodeId);
// This allows everyone to be notified.
if (nodeId > 0 && nodeId <= 232) {
zController.notifyEventListeners(new ZWaveInclusionEvent(ZWaveInclusionEvent.Type.IncludeDone, incomingMessage.getMessagePayloadByte(2)));
}
break;
}
node.resetResendCount();
// Remember that we've received this so we can continue initialisation
node.setApplicationUpdateReceived(true);
// If we're finished initialisation, then we can treat this like a HAIL
if (node.getNodeInitializationStage() == ZWaveNodeInitStage.DONE) {
// If this node supports associations, then assume this should be handled through that mechanism
if (node.getCommandClass(CommandClass.ASSOCIATION) == null) {
// If we receive an Application Update Request and the node is already
// fully initialised we assume this is a request to the controller to
// re-get the current node values
logger.debug("NODE {}: Application update request. Requesting node state.", nodeId);
zController.pollNode(node);
}
} else {
List<Integer> nif = new ArrayList<Integer>();
for (int i = 6; i < length + 3; i++) {
int data = incomingMessage.getMessagePayloadByte(i);
if (data == 0xef) {
// TODO: Implement control command classes
break;
}
logger.trace(String.format("NODE %d: Command class 0x%02X is supported.", nodeId, data));
// See if the command class already exists on the node
CommandClass commandClass = CommandClass.getCommandClass(data);
if (node.getCommandClass(commandClass) == null) {
// add it
ZWaveCommandClass zwaveCommandClass = ZWaveCommandClass.getInstance(data, node, zController);
if (zwaveCommandClass != null) {
logger.trace(String.format("NODE %d: Application update request. Adding Command class %s.", nodeId, commandClass));
node.addCommandClass(zwaveCommandClass);
}
}
}
node.updateNIF(nif);
}
// Notify we received an info frame
zController.notifyEventListeners(new ZWaveNodeInfoEvent(nodeId));
// Treat the node information frame as a wakeup
ZWaveWakeUpCommandClass wakeUp = (ZWaveWakeUpCommandClass) node.getCommandClass(ZWaveCommandClass.CommandClass.WAKE_UP);
if (wakeUp != null) {
wakeUp.setAwake(true);
}
break;
case NODE_INFO_REQ_FAILED:
// Make sure we can correlate the request before we use the nodeId
if (lastSentMessage.getMessageClass() != SerialMessageClass.RequestNodeInfo) {
logger.warn("Got ApplicationUpdateMessage without request, ignoring. Last message was {}.", lastSentMessage.getMessageClass());
return false;
}
// The failed message doesn't contain the node number, so use the info from the request.
nodeId = lastSentMessage.getMessageNode();
logger.debug("NODE {}: Application update request. Node Info Request Failed.", nodeId);
// Handle retries
if (--lastSentMessage.attempts >= 0) {
logger.error("NODE {}: Got Node Info Request Failed. Requeueing", nodeId);
zController.enqueue(lastSentMessage);
} else {
logger.warn("NODE {}: Node Info Request Failed 3x. Discarding message: {}", nodeId, lastSentMessage.toString());
}
// Transaction is not successful
incomingMessage.setTransactionCanceled();
result = false;
break;
default:
logger.warn("TODO: Implement Application Update Request Handling of {} ({}).", updateState.getLabel(), updateState.getKey());
}
// Check if this completes the transaction
checkTransactionComplete(lastSentMessage, incomingMessage);
return result;
}
use of org.openhab.binding.zwave.internal.protocol.commandclass.ZWaveCommandClass in project openhab1-addons by openhab.
the class ApplicationCommandMessageClass method resolveZWaveCommandClass.
/**
* Takes the given commandClassCode and tries to instantiate the corresponding {@link ZWaveCommandClass}
* for the given node
*
* @return the zwave command class for this node or null if it is not possible
*/
private ZWaveCommandClass resolveZWaveCommandClass(ZWaveNode node, int commandClassCode, ZWaveController zController) {
CommandClass commandClass = CommandClass.getCommandClass(commandClassCode & 0xff);
if (commandClass == null) {
logger.error(String.format("NODE %d: Unsupported command class 0x%02x", node.getNodeId(), commandClassCode));
return null;
}
logger.debug(String.format("NODE %d: Incoming command class %s (0x%02x)", node.getNodeId(), commandClass.getLabel(), commandClass.getKey()));
ZWaveCommandClass zwaveCommandClass = node.getCommandClass(commandClass);
// Let's add it now then to support handling this message.
if (zwaveCommandClass == null) {
logger.debug(String.format("NODE %d: Command class %s (0x%02x) not found, trying to add it.", node.getNodeId(), commandClass.getLabel(), commandClass.getKey()));
zwaveCommandClass = ZWaveCommandClass.getInstance(commandClass.getKey(), node, zController);
if (zwaveCommandClass == null) {
// We got an unsupported command class, leave zwaveCommandClass as null
logger.error(String.format("NODE %d: Unsupported zwave command class %s (0x%02x)", node.getNodeId(), commandClass.getLabel(), commandClassCode));
} else {
logger.debug(String.format("NODE %d: Adding command class %s (0x%02x)", node.getNodeId(), commandClass.getLabel(), commandClass.getKey()));
node.addCommandClass(zwaveCommandClass);
}
}
return zwaveCommandClass;
}
use of org.openhab.binding.zwave.internal.protocol.commandclass.ZWaveCommandClass in project openhab1-addons by openhab.
the class ApplicationCommandMessageClass method handleRequest.
@Override
public boolean handleRequest(ZWaveController zController, SerialMessage lastSentMessage, SerialMessage incomingMessage) {
logger.trace("Handle Message Application Command Request");
int nodeId = incomingMessage.getMessagePayloadByte(1);
ZWaveNode node = zController.getNode(nodeId);
if (node == null) {
logger.warn("NODE {}: Not initialized yet, ignoring message.", nodeId);
return false;
}
logger.debug("NODE {}: Application Command Request ({}:{})", nodeId, node.getNodeState().toString(), node.getNodeInitializationStage().toString());
// If the node is DEAD, but we've just received a message from it, then it's not dead!
if (node.isDead()) {
node.setNodeState(ZWaveNodeState.ALIVE);
}
node.resetResendCount();
node.incrementReceiveCount();
int commandClassCode = incomingMessage.getMessagePayloadByte(3);
ZWaveCommandClass zwaveCommandClass = resolveZWaveCommandClass(node, commandClassCode, zController);
if (zwaveCommandClass == null) {
// Error message was logged in resolveZWaveCommandClass
return false;
}
final int commandByte = incomingMessage.getMessagePayloadByte(4);
if (zwaveCommandClass instanceof ZWaveSecurityCommandClass && (ZWaveSecurityCommandClass.bytesAreEqual(ZWaveSecurityCommandClass.SECURITY_MESSAGE_ENCAP, commandByte) || ZWaveSecurityCommandClass.bytesAreEqual(ZWaveSecurityCommandClass.SECURITY_MESSAGE_ENCAP_NONCE_GET, commandByte))) {
boolean isEncapNonceGet = ZWaveSecurityCommandClass.bytesAreEqual(ZWaveSecurityCommandClass.SECURITY_MESSAGE_ENCAP_NONCE_GET, commandByte);
// Intercept security encapsulated messages here and decrypt them.
ZWaveSecurityCommandClass zwaveSecurityCommandClass = (ZWaveSecurityCommandClass) zwaveCommandClass;
logger.trace("NODE {}: Preparing to decrypt security encapsulated message, messagePayload={}", nodeId, SerialMessage.bb2hex(incomingMessage.getMessagePayload()));
int toDecryptLength = incomingMessage.getMessageBuffer().length - 9;
byte[] toDecrypt = new byte[toDecryptLength];
System.arraycopy(incomingMessage.getMessageBuffer(), 8, toDecrypt, 0, toDecryptLength);
byte[] decryptedBytes = zwaveSecurityCommandClass.decryptMessage(toDecrypt, 0);
if (decryptedBytes == null) {
logger.error("NODE {}: Failed to decrypt message out of {} .", nodeId, incomingMessage);
} else {
// call handleApplicationCommandRequest with the decrypted message. Note that we do NOT set
// incomingMessage as that needs to be processed below with the original security encapsulated message
final SerialMessage decryptedMessage = new SerialMessage(incomingMessage.getMessageClass(), incomingMessage.getMessageType(), incomingMessage.getExpectedReply(), incomingMessage.getPriority());
decryptedMessage.setMessagePayload(decryptedBytes);
// Get the new command class with the decrypted contents
zwaveCommandClass = resolveZWaveCommandClass(node, decryptedBytes[1], zController);
// Use a flag bc we need to handle isEncapNonceGet either way
boolean failed = false;
if (zwaveCommandClass == null) {
// Error message was logged in resolveZWaveCommandClass
failed = true;
} else {
// Note that we do not call node.doesMessageRequireSecurityEncapsulation since it was encapsulated.
// Messages that are not required to be are allowed to be, just not the other way around
logger.debug("NODE {}: After decrypt, found Command Class {}, passing to handleApplicationCommandRequest", nodeId, zwaveCommandClass.getCommandClass().getLabel());
zwaveCommandClass.handleApplicationCommandRequest(decryptedMessage, 2, 0);
}
if (isEncapNonceGet) {
// the device also needs another nonce; send it regardless of the success/failure of decryption
zwaveSecurityCommandClass.sendNonceReport();
}
if (failed) {
return false;
}
}
} else {
// Message does not require decryption
if (node.doesMessageRequireSecurityEncapsulation(incomingMessage)) {
// Should have been security encapsulation but wasn't!
logger.error("NODE {}: Command Class {} {} was required to be security encapsulation but it wasn't! Dropping message.", nodeId, zwaveCommandClass.getCommandClass().getKey(), zwaveCommandClass.getCommandClass().getLabel());
// do not call zwaveCommandClass.handleApplicationCommandRequest();
} else {
logger.trace("NODE {}: Found Command Class {}, passing to handleApplicationCommandRequest", nodeId, zwaveCommandClass.getCommandClass().getLabel());
zwaveCommandClass.handleApplicationCommandRequest(incomingMessage, 4, 0);
}
}
if (node.getNodeId() == lastSentMessage.getMessageNode()) {
checkTransactionComplete(lastSentMessage, incomingMessage);
} else {
logger.debug("NODE {}: Transaction not completed: node address inconsistent. lastSent={}, incoming={}", lastSentMessage.getMessageNode(), lastSentMessage.getMessageNode(), incomingMessage.getMessageNode());
}
return true;
}
use of org.openhab.binding.zwave.internal.protocol.commandclass.ZWaveCommandClass in project openhab1-addons by openhab.
the class IdentifyNodeMessageClass method handleResponse.
@Override
public boolean handleResponse(ZWaveController zController, SerialMessage lastSentMessage, SerialMessage incomingMessage) {
logger.trace("Handle Message Get Node ProtocolInfo Response");
// Check that this request is consistent with the response
if (lastSentMessage.getMessageClass() != SerialMessageClass.IdentifyNode) {
logger.warn("Got IdentifyNodeMessage without request, ignoring. Last message was {}.", lastSentMessage.getMessageClass());
return false;
}
int nodeId = lastSentMessage.getMessagePayloadByte(0);
logger.debug("NODE {}: ProtocolInfo", nodeId);
ZWaveNode node = zController.getNode(nodeId);
boolean listening = (incomingMessage.getMessagePayloadByte(0) & 0x80) != 0 ? true : false;
boolean routing = (incomingMessage.getMessagePayloadByte(0) & 0x40) != 0 ? true : false;
int version = (incomingMessage.getMessagePayloadByte(0) & 0x07) + 1;
boolean frequentlyListening = (incomingMessage.getMessagePayloadByte(1) & 0x60) != 0 ? true : false;
boolean beaming = ((incomingMessage.getMessagePayloadByte(1) & 0x10) != 0);
boolean security = ((incomingMessage.getMessagePayloadByte(1) & 0x01) != 0);
int maxBaudRate = 9600;
if ((incomingMessage.getMessagePayloadByte(0) & 0x38) == 0x10) {
maxBaudRate = 40000;
}
logger.debug("NODE {}: Listening = {}", nodeId, listening);
logger.debug("NODE {}: Routing = {}", nodeId, routing);
logger.debug("NODE {}: Beaming = {}", nodeId, beaming);
logger.debug("NODE {}: Version = {}", nodeId, version);
logger.debug("NODE {}: FLIRS = {}", nodeId, frequentlyListening);
logger.debug("NODE {}: Security = {}", nodeId, security);
logger.debug("NODE {}: Max Baud = {}", nodeId, maxBaudRate);
node.setListening(listening);
node.setRouting(routing);
node.setVersion(version);
node.setFrequentlyListening(frequentlyListening);
node.setSecurity(security);
node.setBeaming(beaming);
node.setMaxBaud(maxBaudRate);
Basic basic = Basic.getBasic(incomingMessage.getMessagePayloadByte(3));
if (basic == null) {
logger.error(String.format("NODE %d: Basic device class 0x%02x not found", nodeId, incomingMessage.getMessagePayloadByte(3)));
return false;
}
logger.debug("NODE {}: Basic = {}", nodeId, basic.getLabel());
Generic generic = Generic.getGeneric(incomingMessage.getMessagePayloadByte(4));
if (generic == null) {
logger.error(String.format("NODE %d: Generic device class 0x%02x not found", nodeId, incomingMessage.getMessagePayloadByte(4)));
return false;
}
logger.debug("NODE {}: Generic = {}", nodeId, generic.getLabel());
Specific specific = Specific.getSpecific(generic, incomingMessage.getMessagePayloadByte(5));
if (specific == null) {
logger.error(String.format("NODE %d: Specific device class 0x%02x not found", nodeId, incomingMessage.getMessagePayloadByte(5)));
return false;
}
logger.debug("NODE {}: Specific = {}", nodeId, specific.getLabel());
ZWaveDeviceClass deviceClass = node.getDeviceClass();
deviceClass.setBasicDeviceClass(basic);
deviceClass.setGenericDeviceClass(generic);
deviceClass.setSpecificDeviceClass(specific);
// Add mandatory command classes as specified by its generic device class.
for (CommandClass commandClass : generic.getMandatoryCommandClasses()) {
ZWaveCommandClass zwaveCommandClass = ZWaveCommandClass.getInstance(commandClass.getKey(), node, zController);
if (zwaveCommandClass != null) {
zController.getNode(nodeId).addCommandClass(zwaveCommandClass);
}
}
// Add mandatory command classes as specified by its specific device class.
for (CommandClass commandClass : specific.getMandatoryCommandClasses()) {
ZWaveCommandClass zwaveCommandClass = ZWaveCommandClass.getInstance(commandClass.getKey(), node, zController);
if (zwaveCommandClass != null) {
node.addCommandClass(zwaveCommandClass);
}
}
checkTransactionComplete(lastSentMessage, incomingMessage);
return true;
}
use of org.openhab.binding.zwave.internal.protocol.commandclass.ZWaveCommandClass in project openhab1-addons by openhab.
the class ZWaveNode method addCommandClass.
/**
* Adds a command class to the list of supported command classes by this node.
* Does nothing if command class is already added.
*
* @param commandClass the command class instance to add.
*/
public void addCommandClass(ZWaveCommandClass commandClass) {
CommandClass key = commandClass.getCommandClass();
if (!supportedCommandClasses.containsKey(key)) {
logger.debug("NODE {}: Adding command class {} to the list of supported command classes.", nodeId, commandClass.getCommandClass().getLabel());
supportedCommandClasses.put(key, commandClass);
if (commandClass instanceof ZWaveEventListener) {
this.controller.addEventListener((ZWaveEventListener) commandClass);
}
}
}
Aggregations