use of org.openhab.binding.zwave.internal.protocol.ZWaveAssociation in project org.openhab.binding.zwave by openhab.
the class ZWaveThingHandler method ZWaveIncomingEvent.
@Override
public void ZWaveIncomingEvent(ZWaveEvent incomingEvent) {
// Check if this event is for this device
if (incomingEvent.getNodeId() != nodeId) {
return;
}
logger.debug("NODE {}: Got an event from Z-Wave network: {}", nodeId, incomingEvent.getClass().getSimpleName());
// Handle command class value events.
if (incomingEvent instanceof ZWaveCommandClassValueEvent) {
// Cast to a command class event
ZWaveCommandClassValueEvent event = (ZWaveCommandClassValueEvent) incomingEvent;
String commandClass = event.getCommandClass().toString();
logger.debug("NODE {}: Got a value event from Z-Wave network, endpoint={}, command class={}, value={}", nodeId, event.getEndpoint(), commandClass, event.getValue());
// If this is a configuration parameter update, process it before the channels
Configuration configuration = editConfiguration();
boolean cfgUpdated = false;
switch(event.getCommandClass()) {
case COMMAND_CLASS_CONFIGURATION:
ZWaveConfigurationParameter parameter = ((ZWaveConfigurationParameterEvent) event).getParameter();
if (parameter == null) {
return;
}
logger.debug("NODE {}: Update CONFIGURATION {}/{} to {}", nodeId, parameter.getIndex(), parameter.getSize(), parameter.getValue());
// Check for any sub parameter processing...
// If we have requested the current state of a parameter and t's waiting to be updated, then we
// check this here, update the value and send the request...
// Do this first so we only process the data if we're not waiting to send
ZWaveConfigSubParameter subParameter = subParameters.get(parameter.getIndex());
if (subParameter != null) {
// Get the new value based on the sub-parameter bitmask
int value = subParameter.getValue(parameter.getValue());
logger.debug("NODE {}: Updating sub-parameter {} to {}", nodeId, parameter.getIndex(), value);
// Remove the sub parameter so we don't loop forever!
subParameters.remove(parameter.getIndex());
ZWaveNode node = controllerHandler.getNode(nodeId);
if (node == null) {
logger.warn("NODE {}: Error getting node for config update", nodeId);
return;
}
ZWaveConfigurationCommandClass configurationCommandClass = (ZWaveConfigurationCommandClass) node.getCommandClass(CommandClass.COMMAND_CLASS_CONFIGURATION);
if (configurationCommandClass == null) {
logger.debug("NODE {}: Error getting configurationCommandClass", nodeId);
return;
}
ZWaveConfigurationParameter cfgParameter = configurationCommandClass.getParameter(parameter.getIndex());
if (cfgParameter == null) {
cfgParameter = new ZWaveConfigurationParameter(parameter.getIndex(), value, parameter.getSize());
} else {
cfgParameter.setValue(value);
}
logger.debug("NODE {}: Setting parameter {} to {}", nodeId, cfgParameter.getIndex(), cfgParameter.getValue());
node.sendMessage(configurationCommandClass.setConfigMessage(cfgParameter));
node.sendMessage(configurationCommandClass.getConfigMessage(parameter.getIndex()));
// Don't process the data - it hasn't been updated yet!
break;
}
updateConfigurationParameter(configuration, parameter.getIndex(), parameter.getSize(), parameter.getValue());
break;
case COMMAND_CLASS_ASSOCIATION:
case COMMAND_CLASS_MULTI_CHANNEL_ASSOCIATION:
int groupId = ((ZWaveAssociationEvent) event).getGroupId();
List<ZWaveAssociation> groupMembers = ((ZWaveAssociationEvent) event).getGroupMembers();
// getAssociationConfigList(ZWaveAssociationGroup newMembers) ;
// if (groupMembers != null) {
// logger.debug("NODE {}: Update ASSOCIATION group_{}", nodeId, groupId);
// List<String> group = new ArrayList<String>();
// Build the configuration value
// for (ZWaveAssociation groupMember : groupMembers) {
// logger.debug("NODE {}: Update ASSOCIATION group_{}: Adding {}", nodeId, groupId,
// groupMember);
// group.add(groupMember.toString());
// }
// logger.debug("NODE {}: Update ASSOCIATION group_{}: {} members", nodeId, groupId, group.size());
// cfgUpdated = true;
configuration.put("group_" + groupId, getAssociationConfigList(groupMembers));
removePendingConfig("group_" + groupId);
// }
break;
case COMMAND_CLASS_SWITCH_ALL:
cfgUpdated = true;
configuration.put(ZWaveBindingConstants.CONFIGURATION_SWITCHALLMODE, event.getValue());
removePendingConfig(ZWaveBindingConstants.CONFIGURATION_SWITCHALLMODE);
break;
case COMMAND_CLASS_NODE_NAMING:
switch((ZWaveNodeNamingCommandClass.Type) event.getType()) {
case NODENAME_LOCATION:
cfgUpdated = true;
configuration.put(ZWaveBindingConstants.CONFIGURATION_NODELOCATION, event.getValue());
removePendingConfig(ZWaveBindingConstants.CONFIGURATION_NODELOCATION);
break;
case NODENAME_NAME:
cfgUpdated = true;
configuration.put(ZWaveBindingConstants.CONFIGURATION_NODENAME, event.getValue());
removePendingConfig(ZWaveBindingConstants.CONFIGURATION_NODENAME);
break;
}
break;
case COMMAND_CLASS_DOOR_LOCK:
switch((ZWaveDoorLockCommandClass.Type) event.getType()) {
case DOOR_LOCK_TIMEOUT:
cfgUpdated = true;
configuration.put(ZWaveBindingConstants.CONFIGURATION_DOORLOCKTIMEOUT, event.getValue());
removePendingConfig(ZWaveBindingConstants.CONFIGURATION_DOORLOCKTIMEOUT);
break;
default:
break;
}
break;
case COMMAND_CLASS_USER_CODE:
ZWaveUserCodeValueEvent codeEvent = (ZWaveUserCodeValueEvent) event;
cfgUpdated = true;
String codeParameterName = ZWaveBindingConstants.CONFIGURATION_USERCODE_CODE + codeEvent.getId();
if (codeEvent.getStatus() == UserIdStatusType.OCCUPIED) {
configuration.put(codeParameterName, codeEvent.getCode());
} else {
configuration.put(codeParameterName, "");
}
removePendingConfig(codeParameterName);
break;
default:
break;
}
if (cfgUpdated == true) {
logger.debug("NODE {}: Config updated", nodeId);
updateConfiguration(configuration);
}
if (thingChannelsState == null) {
logger.debug("NODE {}: No state handlers!", nodeId);
return;
}
// Process the channels to see if we're interested
for (ZWaveThingChannel channel : thingChannelsState) {
logger.trace("NODE {}: Checking channel={}, cmdClass={}, endpoint={}", nodeId, channel.getUID(), channel.getCommandClass(), channel.getEndpoint());
if (channel.getEndpoint() != event.getEndpoint()) {
continue;
}
// Is this command class associated with this channel?
if (!channel.getCommandClass().equals(commandClass)) {
continue;
}
if (channel.getConverter() == null) {
logger.warn("NODE {}: No state converter set for channel {}", nodeId, channel.getUID());
return;
}
// logger.debug("NODE {}: Processing event as channel {} {}", nodeId, channel.getUID(),
// channel.dataType);
State state = channel.getConverter().handleEvent(channel, event);
if (state != null) {
logger.debug("NODE {}: Updating channel state {} to {} [{}]", nodeId, channel.getUID(), state, state.getClass().getSimpleName());
updateState(channel.getUID(), state);
}
}
return;
}
// Handle transaction complete events.
if (incomingEvent instanceof ZWaveTransactionCompletedEvent) {
return;
}
// Handle wakeup notification events.
if (incomingEvent instanceof ZWaveWakeUpEvent) {
ZWaveNode node = controllerHandler.getNode(nodeId);
if (node == null) {
return;
}
switch(((ZWaveWakeUpEvent) incomingEvent).getEvent()) {
case ZWaveWakeUpCommandClass.WAKE_UP_INTERVAL_REPORT:
ZWaveWakeUpCommandClass commandClass = (ZWaveWakeUpCommandClass) node.getCommandClass(CommandClass.COMMAND_CLASS_WAKE_UP);
Configuration configuration = editConfiguration();
configuration.put(ZWaveBindingConstants.CONFIGURATION_WAKEUPINTERVAL, commandClass.getInterval());
removePendingConfig(ZWaveBindingConstants.CONFIGURATION_WAKEUPINTERVAL);
configuration.put(ZWaveBindingConstants.CONFIGURATION_WAKEUPNODE, commandClass.getTargetNodeId());
removePendingConfig(ZWaveBindingConstants.CONFIGURATION_WAKEUPNODE);
updateConfiguration(configuration);
break;
}
return;
}
// Handle node state change events.
if (incomingEvent instanceof ZWaveNodeStatusEvent) {
// Cast to a command class event
ZWaveNodeStatusEvent event = (ZWaveNodeStatusEvent) incomingEvent;
switch(event.getState()) {
case AWAKE:
Map<String, String> properties = editProperties();
properties.put(ZWaveBindingConstants.PROPERTY_LASTWAKEUP, getISO8601StringForCurrentDate());
updateProperties(properties);
break;
case ASLEEP:
break;
case INITIALIZING:
case ALIVE:
logger.debug("NODE {}: Setting ONLINE", nodeId);
updateStatus(ThingStatus.ONLINE);
break;
case DEAD:
case FAILED:
logger.debug("NODE {}: Setting OFFLINE", nodeId);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, ZWaveBindingConstants.OFFLINE_NODE_DEAD);
break;
}
return;
}
if (incomingEvent instanceof ZWaveInitializationStateEvent) {
ZWaveInitializationStateEvent initEvent = (ZWaveInitializationStateEvent) incomingEvent;
switch(initEvent.getStage()) {
case STATIC_END:
// Update some properties first...
updateNodeProperties();
// Do we need to change type?
if (finalTypeSet == false) {
if (updateThingType() == true) {
// The thing will have already been disposed of so let's get the hell out of here!
return;
}
}
if (finalTypeSet) {
// Now that this node is initialised, we want to re-process all channels
initialiseNode();
}
break;
case HEAL_START:
break;
case HEAL_END:
Map<String, String> properties = editProperties();
properties.put(ZWaveBindingConstants.PROPERTY_LASTHEAL, getISO8601StringForCurrentDate());
updateProperties(properties);
break;
// Don't update the thing state for dynamic updates - this is just polling
case DYNAMIC_VALUES:
case DYNAMIC_END:
break;
// Don't update the thing state when doing a heal
case UPDATE_NEIGHBORS:
case GET_NEIGHBORS:
case DELETE_SUC_ROUTES:
case SUC_ROUTE:
case DELETE_ROUTES:
case RETURN_ROUTES:
break;
case DONE:
updateStatus(ThingStatus.ONLINE);
break;
default:
if (finalTypeSet) {
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE, "Node initialising: " + initEvent.getStage().toString());
}
break;
}
}
if (incomingEvent instanceof ZWaveNetworkEvent) {
ZWaveNetworkEvent networkEvent = (ZWaveNetworkEvent) incomingEvent;
if (networkEvent.getEvent() == ZWaveNetworkEvent.Type.NodeRoutingInfo) {
updateNodeNeighbours();
}
if (networkEvent.getEvent() == ZWaveNetworkEvent.Type.DeleteNode) {
// TODO: Update to THING_GONE
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE);
}
}
if (incomingEvent instanceof ZWaveDelayedPollEvent) {
long delay = ((ZWaveDelayedPollEvent) incomingEvent).getDelay();
TimeUnit unit = ((ZWaveDelayedPollEvent) incomingEvent).getUnit();
// Don't create a poll beyond our max value
if (unit.toSeconds(delay) > DELAYED_POLLING_PERIOD_MAX) {
delay = DELAYED_POLLING_PERIOD_MAX;
unit = TimeUnit.SECONDS;
}
startPolling(unit.toMillis(delay));
}
// Handle exclusion of this node
if (incomingEvent instanceof ZWaveInclusionEvent) {
ZWaveInclusionEvent incEvent = (ZWaveInclusionEvent) incomingEvent;
if (incEvent.getNodeId() != nodeId) {
return;
}
switch(incEvent.getEvent()) {
case ExcludeDone:
// Let our users know we're gone!
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "Node was excluded from the controller");
// Remove the XML file
ZWaveNodeSerializer nodeSerializer = new ZWaveNodeSerializer();
nodeSerializer.deleteNode(controllerHandler.getHomeId(), nodeId);
// Stop polling
synchronized (pollingSync) {
if (pollingJob != null) {
pollingJob.cancel(true);
pollingJob = null;
}
}
break;
default:
break;
}
}
}
use of org.openhab.binding.zwave.internal.protocol.ZWaveAssociation in project org.openhab.binding.zwave by openhab.
the class ZWaveAssociationCommandClass method handleAssociationReport.
/**
* Processes a ASSOCIATIONCMD_REPORT message.
*
* @param serialMessage
* the incoming message to process.
* @param offset
* the offset position from which to start message processing.
* @throws ZWaveSerialMessageException
*/
@ZWaveResponseHandler(id = ASSOCIATIONCMD_REPORT, name = "ASSOCIATIONCMD_REPORT")
public void handleAssociationReport(ZWaveCommandClassPayload payload, int endpoint) {
// Extract the group index
int group = payload.getPayloadByte(2);
// The max associations supported (0 if the requested group is not supported)
int maxAssociations = payload.getPayloadByte(3);
// Number of outstanding requests (if the group is large, it may come in multiple frames)
int following = payload.getPayloadByte(4);
if (maxAssociations == 0) {
// Unsupported association group. Nothing to do!
if (updateAssociationsNode == group) {
logger.debug("NODE {}: All association groups acquired.", getNode().getNodeId());
updateAssociationsNode = 0;
// This is used for network management, so send a network event
getController().notifyEventListeners(new ZWaveNetworkEvent(ZWaveNetworkEvent.Type.AssociationUpdate, getNode().getNodeId(), ZWaveNetworkEvent.State.Success));
}
return;
}
logger.debug("NODE {}: association group {} has max associations {}", getNode().getNodeId(), group, maxAssociations);
// Are we waiting to synchronise the start of a new group?
if (pendingAssociation == null) {
pendingAssociation = new ZWaveAssociationGroup(group);
}
if (payload.getPayloadLength() > 4) {
logger.debug("NODE {}: association group {} includes the following nodes:", getNode().getNodeId(), group);
int numAssociations = payload.getPayloadLength() - (5);
for (int cnt = 0; cnt < numAssociations; cnt++) {
int node = payload.getPayloadByte(5 + cnt);
logger.debug("Node {}", node);
// Add the node to the group
pendingAssociation.addAssociation(new ZWaveAssociation(node));
}
}
// If this is the end of the group, update the list then let the listeners know
if (following == 0) {
// Update the group in the list
getNode().getAssociationGroup(pendingAssociation.getIndex()).setAssociations(pendingAssociation.getAssociations());
// Send an event to the users
ZWaveAssociationEvent zEvent = new ZWaveAssociationEvent(getNode().getNodeId(), pendingAssociation);
pendingAssociation = null;
getController().notifyEventListeners(zEvent);
}
// Is this the end of the list
if (following == 0 && group == updateAssociationsNode) {
// so we need to request the next group
if (updateAssociationsNode < maxGroups) {
updateAssociationsNode++;
ZWaveCommandClassTransactionPayload outputMessage = getAssociationMessage(updateAssociationsNode);
if (outputMessage != null) {
getController().sendData(outputMessage);
}
} else {
logger.debug("NODE {}: All association groups acquired.", getNode().getNodeId());
// We have reached our maxNodes, notify listeners we are done.
updateAssociationsNode = 0;
// This is used for network management, so send a network event
getController().notifyEventListeners(new ZWaveNetworkEvent(ZWaveNetworkEvent.Type.AssociationUpdate, getNode().getNodeId(), ZWaveNetworkEvent.State.Success));
}
}
}
use of org.openhab.binding.zwave.internal.protocol.ZWaveAssociation in project org.openhab.binding.zwave by openhab.
the class ZWaveMultiAssociationCommandClass method handleMultiAssociationReport.
/**
* Processes a MULTI_ASSOCIATIONCMD_REPORT message.
*
* @param serialMessage
* the incoming message to process.
* @param offset
* the offset position from which to start message processing.
* @throws ZWaveSerialMessageException
*/
@ZWaveResponseHandler(id = MULTI_ASSOCIATIONCMD_REPORT, name = "MULTI_ASSOCIATIONCMD_REPORT")
public void handleMultiAssociationReport(ZWaveCommandClassPayload payload, int endpoint) {
// Extract the group index
int group = payload.getPayloadByte(2);
// The max associations supported (0 if the requested group is not supported)
int maxAssociations = payload.getPayloadByte(3);
// Number of outstanding requests (if the group is large, it may come in multiple frames)
int following = payload.getPayloadByte(4);
if (maxAssociations == 0) {
// Unsupported association group. Nothing to do!
if (updateAssociationsNode == group) {
logger.debug("NODE {}: All association groups acquired.", getNode().getNodeId());
updateAssociationsNode = 0;
// This is used for network management, so send a network event
getController().notifyEventListeners(new ZWaveNetworkEvent(ZWaveNetworkEvent.Type.AssociationUpdate, getNode().getNodeId(), ZWaveNetworkEvent.State.Success));
}
return;
}
logger.debug("NODE {}: association group {} has max associations {}", getNode().getNodeId(), group, maxAssociations);
// Are we waiting to synchronise the start of a new group?
if (pendingAssociation == null) {
pendingAssociation = new ZWaveAssociationGroup(group);
}
if (payload.getPayloadLength() > 5) {
logger.debug("NODE {}: Association group {} includes the following nodes:", getNode().getNodeId(), group);
int dataLength = payload.getPayloadLength() - 5;
int dataPointer = 0;
// Process the root associations
for (; dataPointer < dataLength; dataPointer++) {
int node = payload.getPayloadByte(5 + dataPointer);
if (node == MULTI_INSTANCE_MARKER) {
break;
}
logger.debug("NODE {}: Associated with Node {} in group {}", getNode().getNodeId(), node, group);
// Add the node to the group
pendingAssociation.addAssociation(new ZWaveAssociation(node));
}
// Process the multi instance associations
if (dataPointer < dataLength) {
logger.trace("NODE {}: Includes multi_instance associations", getNode().getNodeId());
// Step over the marker
dataPointer++;
for (; dataPointer < dataLength; dataPointer += 2) {
int node = payload.getPayloadByte(5 + dataPointer);
int endpointId = payload.getPayloadByte(6 + dataPointer);
if (node == MULTI_INSTANCE_MARKER) {
break;
}
logger.debug("NODE {}: Associated with Node {} endpoint {} in group", getNode().getNodeId(), node, endpointId, group);
// Add the node to the group
pendingAssociation.addAssociation(new ZWaveAssociation(node, endpointId));
}
}
}
// If this is the end of the group, update the list then let the listeners know
if (following == 0) {
// Clear the current information for this group
ZWaveAssociationGroup associationGroup = getNode().getAssociationGroup(group);
if (associationGroup != null) {
// Update the group in the list
getNode().getAssociationGroup(pendingAssociation.getIndex()).setAssociations(pendingAssociation.getAssociations());
}
// Send an event to the users
ZWaveAssociationEvent zEvent = new ZWaveAssociationEvent(getNode().getNodeId(), pendingAssociation);
pendingAssociation = null;
getController().notifyEventListeners(zEvent);
}
// Is this the end of the list
if (following == 0 && group == updateAssociationsNode) {
// so we need to request the next group
if (updateAssociationsNode < maxGroups) {
updateAssociationsNode++;
ZWaveCommandClassTransactionPayload transaction = getAssociationMessage(updateAssociationsNode);
if (transaction != null) {
getController().sendData(transaction);
}
} else {
logger.debug("NODE {}: All association groups acquired.", getNode().getNodeId());
// We have reached our maxNodes, notify listeners we are done.
updateAssociationsNode = 0;
// This is used for network management, so send a network event
getController().notifyEventListeners(new ZWaveNetworkEvent(ZWaveNetworkEvent.Type.AssociationUpdate, getNode().getNodeId(), ZWaveNetworkEvent.State.Success));
}
}
}
use of org.openhab.binding.zwave.internal.protocol.ZWaveAssociation in project org.openhab.binding.zwave by openhab.
the class ZWaveThingHandler method updateNodeProperties.
private void updateNodeProperties() {
if (controllerHandler == null) {
logger.debug("NODE {}: Updating node properties. Controller not found.", nodeId);
return;
}
ZWaveNode node = controllerHandler.getNode(nodeId);
if (node == null) {
logger.debug("NODE {}: Updating node properties. Node not found.", nodeId);
return;
}
logger.debug("NODE {}: Updating node properties.", nodeId);
// Update property information about this device
Map<String, String> properties = editProperties();
updateProperty(ZWaveBindingConstants.PROPERTY_NODEID, Integer.toString(nodeId));
logger.debug("NODE {}: Updating node properties. MAN={}", nodeId, node.getManufacturer());
if (node.getManufacturer() != Integer.MAX_VALUE) {
logger.debug("NODE {}: Updating node properties. MAN={}. SET. Was {}", nodeId, node.getManufacturer(), properties.get(ZWaveBindingConstants.PROPERTY_MANUFACTURER));
properties.put(ZWaveBindingConstants.PROPERTY_MANUFACTURER, Integer.toString(node.getManufacturer()));
}
if (node.getDeviceType() != Integer.MAX_VALUE) {
properties.put(ZWaveBindingConstants.PROPERTY_DEVICETYPE, Integer.toString(node.getDeviceType()));
}
if (node.getDeviceId() != Integer.MAX_VALUE) {
properties.put(ZWaveBindingConstants.PROPERTY_DEVICEID, Integer.toString(node.getDeviceId()));
}
properties.put(ZWaveBindingConstants.PROPERTY_VERSION, node.getApplicationVersion());
properties.put(ZWaveBindingConstants.PROPERTY_CLASS_BASIC, node.getDeviceClass().getBasicDeviceClass().toString());
properties.put(ZWaveBindingConstants.PROPERTY_CLASS_GENERIC, node.getDeviceClass().getGenericDeviceClass().toString());
properties.put(ZWaveBindingConstants.PROPERTY_CLASS_SPECIFIC, node.getDeviceClass().getSpecificDeviceClass().toString());
properties.put(ZWaveBindingConstants.PROPERTY_LISTENING, Boolean.toString(node.isListening()));
properties.put(ZWaveBindingConstants.PROPERTY_FREQUENT, Boolean.toString(node.isFrequentlyListening()));
properties.put(ZWaveBindingConstants.PROPERTY_BEAMING, Boolean.toString(node.isBeaming()));
properties.put(ZWaveBindingConstants.PROPERTY_ROUTING, Boolean.toString(node.isRouting()));
properties.put(ZWaveBindingConstants.PROPERTY_USINGSECURITY, Boolean.toString(node.isSecure()));
// If this is a Z-Wave Plus device, then also add its class
ZWavePlusCommandClass cmdClassZWavePlus = (ZWavePlusCommandClass) node.getCommandClass(CommandClass.COMMAND_CLASS_ZWAVEPLUS_INFO);
if (cmdClassZWavePlus != null) {
properties.put(ZWaveBindingConstants.PROPERTY_ZWPLUS_DEVICETYPE, cmdClassZWavePlus.getNodeType());
properties.put(ZWaveBindingConstants.PROPERTY_ZWPLUS_ROLETYPE, cmdClassZWavePlus.getRoleType());
}
// Must loop over the new properties since we might have added data
boolean update = false;
Map<String, String> originalProperties = editProperties();
for (String property : properties.keySet()) {
if ((originalProperties.get(property) == null || originalProperties.get(property).equals(properties.get(property)) == false)) {
update = true;
break;
}
}
update = true;
if (update == true) {
logger.debug("NODE {}: Properties synchronised", nodeId);
updateProperties(properties);
}
// We need to synchronise the configuration between the ZWave library and ESH.
// This is especially important when the device is first added as the ESH representation of the config
// will be set to defaults. We will also not have any defaults for association groups, wakeup etc.
Configuration config = editConfiguration();
// Process CONFIGURATION
ZWaveConfigurationCommandClass configurationCommandClass = (ZWaveConfigurationCommandClass) node.getCommandClass(CommandClass.COMMAND_CLASS_CONFIGURATION);
if (configurationCommandClass != null) {
// Iterate over all parameters and process
for (int paramId : configurationCommandClass.getParameters().keySet()) {
ZWaveConfigurationParameter parameter = configurationCommandClass.getParameter(paramId);
updateConfigurationParameter(config, parameter.getIndex(), parameter.getSize(), parameter.getValue());
}
}
// Process ASSOCIATION
for (ZWaveAssociationGroup group : node.getAssociationGroups().values()) {
List<String> members = new ArrayList<String>();
// Build the configuration value
for (ZWaveAssociation groupMember : group.getAssociations()) {
if (groupMember.getNode() == controllerHandler.getOwnNodeId()) {
logger.debug("NODE {}: Update ASSOCIATION group_{}: Adding Controller ({})", nodeId, group, groupMember);
members.add(ZWaveBindingConstants.GROUP_CONTROLLER);
} else {
logger.debug("NODE {}: Update ASSOCIATION group_{}: Adding {}", nodeId, group, groupMember);
members.add(groupMember.toString());
}
}
config.put("group_" + group.getIndex(), members);
}
// Process WAKE_UP
ZWaveWakeUpCommandClass wakeupCommandClass = (ZWaveWakeUpCommandClass) node.getCommandClass(CommandClass.COMMAND_CLASS_WAKE_UP);
if (wakeupCommandClass != null) {
config.put(ZWaveBindingConstants.CONFIGURATION_WAKEUPINTERVAL, wakeupCommandClass.getInterval());
config.put(ZWaveBindingConstants.CONFIGURATION_WAKEUPNODE, wakeupCommandClass.getTargetNodeId());
}
// Process SWITCH_ALL
ZWaveSwitchAllCommandClass switchallCommandClass = (ZWaveSwitchAllCommandClass) node.getCommandClass(CommandClass.COMMAND_CLASS_SWITCH_ALL);
if (switchallCommandClass != null) {
if (switchallCommandClass.getMode() != null) {
config.put(ZWaveBindingConstants.CONFIGURATION_SWITCHALLMODE, switchallCommandClass.getMode().getMode());
}
}
// Process NODE_NAMING
ZWaveNodeNamingCommandClass nodenamingCommandClass = (ZWaveNodeNamingCommandClass) node.getCommandClass(CommandClass.COMMAND_CLASS_NODE_NAMING);
if (nodenamingCommandClass != null) {
if (nodenamingCommandClass.getLocation() != null) {
config.put(ZWaveBindingConstants.CONFIGURATION_NODELOCATION, nodenamingCommandClass.getLocation());
}
if (nodenamingCommandClass.getName() != null) {
config.put(ZWaveBindingConstants.CONFIGURATION_NODENAME, nodenamingCommandClass.getName());
}
}
// Only update if configuration has changed
Configuration originalConfig = editConfiguration();
update = false;
for (String property : config.getProperties().keySet()) {
if (config.get(property) != null && config.get(property).equals(originalConfig.get(property)) == false) {
update = true;
break;
}
}
if (update == true) {
logger.debug("NODE {}: Configuration synchronised", nodeId);
updateConfiguration(config);
}
}
use of org.openhab.binding.zwave.internal.protocol.ZWaveAssociation in project org.openhab.binding.zwave by openhab.
the class ZWaveThingHandler method handleConfigurationUpdate.
@Override
public void handleConfigurationUpdate(Map<String, Object> configurationParameters) throws ConfigValidationException {
logger.debug("NODE {}: Configuration update received", nodeId);
// Perform checking on the configuration
validateConfigurationParameters(configurationParameters);
if (controllerHandler == null) {
logger.debug("NODE {}: Configuration update not processed as controller not found", nodeId);
return;
}
ZWaveNode node = controllerHandler.getNode(nodeId);
if (node == null) {
logger.debug("NODE {}: Configuration update not processed as node not found", nodeId);
return;
}
// Wakeup targets are not set immediately during the config as we need to correlate multiple settings
// Record them in these variables and set them at the end if one or both are configured
Integer wakeupNode = null;
Integer wakeupInterval = null;
Configuration configuration = editConfiguration();
for (Entry<String, Object> configurationParameter : configurationParameters.entrySet()) {
Object valueObject = configurationParameter.getValue();
// Ignore any configuration parameters that have not changed
if (Objects.equals(configurationParameter.getValue(), configuration.get(configurationParameter.getKey()))) {
logger.debug("NODE {}: Configuration update ignored {} to {} ({})", nodeId, configurationParameter.getKey(), valueObject, valueObject == null ? "null" : valueObject.getClass().getSimpleName());
continue;
}
logger.debug("NODE {}: Configuration update set {} to {} ({})", nodeId, configurationParameter.getKey(), valueObject, valueObject == null ? "null" : valueObject.getClass().getSimpleName());
String[] cfg = configurationParameter.getKey().split("_");
switch(cfg[0]) {
case "config":
if (cfg.length < 3) {
logger.warn("NODE {}: Configuration invalid {}", nodeId, configurationParameter.getKey());
continue;
}
ZWaveConfigurationCommandClass configurationCommandClass = (ZWaveConfigurationCommandClass) node.getCommandClass(CommandClass.COMMAND_CLASS_CONFIGURATION);
if (configurationCommandClass == null) {
logger.debug("NODE {}: Error getting configurationCommandClass", nodeId);
continue;
}
// Get the size
int size = Integer.parseInt(cfg[2]);
if (size == 0 || size > 4) {
logger.debug("NODE {}: Size error ({}) from {}", nodeId, size, configurationParameter.getKey());
continue;
}
// Convert to integer
Integer value;
if (configurationParameter.getValue() instanceof BigDecimal) {
value = ((BigDecimal) configurationParameter.getValue()).intValue();
} else if (configurationParameter.getValue() instanceof String) {
value = Integer.parseInt((String) configurationParameter.getValue());
} else {
logger.debug("NODE {}: Error converting config value from {}", nodeId, configurationParameter.getValue().getClass());
continue;
}
Integer parameterIndex = Integer.valueOf(cfg[1]);
boolean writeOnly = false;
if (Arrays.asList(cfg).contains("wo")) {
writeOnly = true;
}
// If we have specified a bitmask, then we need to process this and save for later
if (cfg.length >= 4 && cfg[3].length() == 8) {
int bitmask = 0xffffffff;
try {
bitmask = Integer.parseInt(cfg[3], 16);
} catch (NumberFormatException e) {
logger.debug("NODE {}: Error parsing bitmask for {}", nodeId, configurationParameter.getKey());
}
boolean requestUpdate = false;
ZWaveConfigSubParameter subParameter = subParameters.get(parameterIndex);
if (subParameter == null) {
subParameter = new ZWaveConfigSubParameter();
requestUpdate = true;
}
logger.debug("NODE {}: Set sub-parameter {} from {} / {}", nodeId, parameterIndex, value, String.format("%08X", bitmask));
logger.debug("NODE {}: Parameter {} set value {} mask {}", nodeId, parameterIndex, String.format("%08X", value), String.format("%08X", bitmask));
subParameter.addBitmask(bitmask, value);
subParameters.put(parameterIndex, subParameter);
// Only send the request if there's not already a request outstanding
if (requestUpdate == true) {
node.sendMessage(configurationCommandClass.getConfigMessage(parameterIndex));
}
} else {
ZWaveConfigurationParameter cfgParameter = configurationCommandClass.getParameter(parameterIndex);
if (cfgParameter == null) {
cfgParameter = new ZWaveConfigurationParameter(parameterIndex, value, size);
} else {
cfgParameter.setValue(value);
}
// Set the parameter and request a read-back if it's not a write only parameter
node.sendMessage(configurationCommandClass.setConfigMessage(cfgParameter));
if (writeOnly == false) {
node.sendMessage(configurationCommandClass.getConfigMessage(parameterIndex));
}
}
addPendingConfig(configurationParameter.getKey(), valueObject);
break;
case "group":
if (cfg.length < 2) {
logger.debug("NODE {}: Association invalid {}", nodeId, configurationParameter.getKey());
continue;
}
Integer groupIndex = Integer.valueOf(cfg[1]);
// Get the configuration information.
// This should be an array of nodes, and/or nodes and endpoints
ArrayList<String> paramValues = new ArrayList<String>();
Object parameter = configurationParameter.getValue();
if (parameter instanceof List) {
paramValues.addAll((List) configurationParameter.getValue());
} else if (parameter instanceof String) {
String strParam = ((String) parameter).trim();
// It's a kludge, but let's try and handle this format...
if (strParam.startsWith("[") && strParam.endsWith("]")) {
strParam = strParam.substring(1, strParam.length() - 1);
if (strParam.contains(",")) {
String[] splits = strParam.split(",");
for (String split : splits) {
paramValues.add(split.trim());
}
}
} else {
paramValues.add(strParam);
}
}
logger.debug("NODE {}: Association {} consolidated to {}", nodeId, groupIndex, paramValues);
ZWaveAssociationGroup currentMembers = node.getAssociationGroup(groupIndex);
if (currentMembers == null) {
logger.debug("NODE {}: Unknown association group {}", nodeId, groupIndex);
continue;
}
logger.debug("NODE {}: Current members before update {}", nodeId, currentMembers);
ZWaveAssociationGroup newMembers = new ZWaveAssociationGroup(groupIndex);
// Loop over all the values
for (String paramValue : paramValues) {
// Check if this is the controller
if (paramValue.equals(ZWaveBindingConstants.GROUP_CONTROLLER)) {
newMembers.addAssociation(new ZWaveAssociation(controllerHandler.getOwnNodeId(), 1));
} else {
String[] groupCfg = paramValue.split("_");
// Make sure this is a correctly formatted option
if (!"node".equals(groupCfg[0])) {
logger.debug("NODE {}: Invalid association {} ({})", nodeId, paramValue, groupCfg[0]);
continue;
}
int groupNode = Integer.parseInt(groupCfg[1]);
if (groupNode == controllerHandler.getOwnNodeId()) {
logger.debug("NODE {}: Association is for controller", nodeId);
newMembers.addAssociation(new ZWaveAssociation(controllerHandler.getOwnNodeId(), 1));
continue;
}
// Get the node Id and endpoint Id
if (groupCfg.length == 2) {
newMembers.addAssociation(new ZWaveAssociation(groupNode));
} else {
newMembers.addAssociation(new ZWaveAssociation(groupNode, Integer.parseInt(groupCfg[2])));
}
}
}
logger.debug("NODE {}: Members after config update {}", nodeId, newMembers);
if (controllerHandler.isControllerMaster()) {
logger.debug("NODE {}: Controller is master - forcing associations", nodeId);
// Check if this is the lifeline profile
if (newMembers.getProfile1() == 0x00 && newMembers.getProfile2() == 0x01) {
logger.debug("NODE {}: Group is lifeline - forcing association", nodeId);
newMembers.addAssociation(new ZWaveAssociation(controllerHandler.getOwnNodeId(), 1));
}
ThingType thingType = ZWaveConfigProvider.getThingType(node);
if (thingType == null) {
logger.debug("NODE {}: Thing type not found for association check", node.getNodeId());
} else {
String associations = thingType.getProperties().get(ZWaveBindingConstants.PROPERTY_XML_ASSOCIATIONS);
if (associations == null || associations.length() == 0) {
logger.debug("NODE {}: Thing has no default associations", node.getNodeId());
} else {
String[] defaultGroups = associations.split(",");
if (Arrays.asList(defaultGroups).contains(cfg[1])) {
logger.debug("NODE {}: Group is controller - forcing association", nodeId);
newMembers.addAssociation(new ZWaveAssociation(controllerHandler.getOwnNodeId(), 1));
}
}
}
logger.debug("NODE {}: Members after controller update {}", nodeId, newMembers);
}
// This ensures we don't end up with strange ghost associations
if (newMembers.getAssociationCnt() == 0) {
logger.debug("NODE {}: Association group {} contains no members. Clearing.", nodeId, groupIndex);
node.sendMessage(node.clearAssociation(groupIndex));
} else {
// Loop through the current members and remove anything that's not in the new members list
for (ZWaveAssociation member : currentMembers.getAssociations()) {
// Is the current association still in the newMembers list?
if (newMembers.isAssociated(member) == false) {
logger.debug("NODE {}: Removing {} from association group {}", nodeId, member, groupIndex);
// No - so it needs to be removed
node.sendMessage(node.removeAssociation(groupIndex, member));
}
}
// Now loop through the new members and add anything not in the current members list
for (ZWaveAssociation member : newMembers.getAssociations()) {
// Is the new association still in the currentMembers list?
if (currentMembers.isAssociated(member) == false) {
logger.debug("NODE {}: Adding {} to association group {}", nodeId, member, groupIndex);
// No - so it needs to be added
node.sendMessage(node.setAssociation(groupIndex, member));
}
}
}
// Request an update to the association group
node.sendMessage(node.getAssociation(groupIndex));
addPendingConfig(configurationParameter.getKey(), valueObject);
// Create a clean association list
valueObject = getAssociationConfigList(newMembers.getAssociations());
break;
case "wakeup":
if (configurationParameter.getValue() == null) {
logger.debug("NODE {}: Error converting wakeup value null", nodeId);
continue;
}
Integer wakeupValue = null;
try {
wakeupValue = ((BigDecimal) configurationParameter.getValue()).intValue();
} catch (NumberFormatException e) {
logger.debug("NODE {}: Error converting wakeup value {} from {}", nodeId, cfg[1], configurationParameter.getValue());
continue;
}
switch(cfg[1]) {
case "node":
wakeupNode = wakeupValue;
logger.debug("NODE {}: Set wakeup node to '{}'", nodeId, wakeupNode);
break;
case "interval":
wakeupInterval = wakeupValue;
logger.debug("NODE {}: Set wakeup interval to '{}'", nodeId, wakeupInterval);
break;
default:
logger.debug("NODE {}: Unknown wakeup command {}", nodeId, cfg[1]);
break;
}
addPendingConfig(configurationParameter.getKey(), valueObject);
break;
case "nodename":
ZWaveNodeNamingCommandClass nameCommandClass = (ZWaveNodeNamingCommandClass) node.getCommandClass(CommandClass.COMMAND_CLASS_NODE_NAMING);
if (nameCommandClass == null) {
logger.debug("NODE {}: Error getting NodeNamingCommandClass", nodeId);
continue;
}
if (configurationParameter.getValue() == null || !(configurationParameter.getValue() instanceof String)) {
logger.debug("NODE {}: Error setting NodeNamingCommandClass {} to invalid value {}", nodeId, cfg[1], configurationParameter.getValue(), configurationParameter.getValue());
continue;
}
if ("name".equals(cfg[1])) {
node.sendMessage(nameCommandClass.setNameMessage(configurationParameter.getValue().toString()));
}
if ("location".equals(cfg[1])) {
node.sendMessage(nameCommandClass.setLocationMessage(configurationParameter.getValue().toString()));
}
addPendingConfig(configurationParameter.getKey(), valueObject);
break;
case "switchall":
ZWaveSwitchAllCommandClass switchallCommandClass = (ZWaveSwitchAllCommandClass) node.getCommandClass(CommandClass.COMMAND_CLASS_SWITCH_ALL);
if (switchallCommandClass == null) {
logger.debug("NODE {}: Error getting SwitchAllCommandClass", nodeId);
continue;
}
if ("mode".equals(cfg[1])) {
controllerHandler.sendData(node.encapsulate(switchallCommandClass.setValueMessage(Integer.parseInt(configurationParameter.getValue().toString())), 0));
}
addPendingConfig(configurationParameter.getKey(), valueObject);
break;
case "doorlock":
ZWaveDoorLockCommandClass commandClass = (ZWaveDoorLockCommandClass) node.getCommandClass(CommandClass.COMMAND_CLASS_DOOR_LOCK);
if (commandClass == null) {
logger.debug("NODE {}: Error getting ZWaveDoorLockCommandClass", nodeId);
continue;
}
if ("timeout".equals(cfg[1])) {
boolean timeoutEnabled;
try {
int doorlockValue = ((BigDecimal) valueObject).intValue();
if (doorlockValue == 0) {
timeoutEnabled = false;
} else {
timeoutEnabled = true;
}
controllerHandler.sendData(node.encapsulate(commandClass.setConfigMessage(timeoutEnabled, doorlockValue), 0));
controllerHandler.sendData(node.encapsulate(commandClass.getConfigMessage(), 0));
addPendingConfig(ZWaveBindingConstants.CONFIGURATION_DOORLOCKTIMEOUT, valueObject);
} catch (NumberFormatException e) {
logger.debug("Number format exception parsing doorlock_timeout '{}'", valueObject);
}
}
break;
case "usercode":
ZWaveUserCodeCommandClass userCodeCommandClass = (ZWaveUserCodeCommandClass) node.getCommandClass(CommandClass.COMMAND_CLASS_USER_CODE);
if (userCodeCommandClass == null) {
logger.debug("NODE {}: Error getting ZWaveUserCodeCommandClass", nodeId);
continue;
}
if ("code".equals(cfg[1])) {
try {
int code = Integer.parseInt(cfg[2]);
if (code == 0 || code > userCodeCommandClass.getNumberOfSupportedCodes()) {
logger.debug("NODE {}: Attempt to set code ID outside of range", nodeId);
continue;
}
if (valueObject instanceof String) {
controllerHandler.sendData(node.encapsulate(userCodeCommandClass.setUserCode(code, (String) valueObject), 0));
controllerHandler.sendData(node.encapsulate(userCodeCommandClass.getUserCode(code), 0));
addPendingConfig(configurationParameter.getKey(), valueObject);
} else {
logger.warn("Value format error processing user code {}", valueObject);
}
} catch (NumberFormatException e) {
logger.warn("Number format exception parsing user code ID '{}'", configurationParameter.getKey());
}
}
break;
case "binding":
if ("pollperiod".equals(cfg[1])) {
pollingPeriod = POLLING_PERIOD_DEFAULT;
try {
pollingPeriod = ((BigDecimal) configurationParameter.getValue()).intValue();
} catch (final NumberFormatException ex) {
logger.debug("NODE {}: pollingPeriod ({}) cannot be set - using default", nodeId, configurationParameter.getValue().toString());
}
if (pollingPeriod < POLLING_PERIOD_MIN) {
pollingPeriod = POLLING_PERIOD_MIN;
}
if (pollingPeriod > POLLING_PERIOD_MAX) {
pollingPeriod = POLLING_PERIOD_MAX;
}
valueObject = new BigDecimal(pollingPeriod);
// Restart polling so we use the new value
startPolling();
}
if ("cmdrepollperiod".equals(cfg[1])) {
commandPollDelay = REPOLL_PERIOD_DEFAULT;
try {
commandPollDelay = ((BigDecimal) configurationParameter.getValue()).intValue();
} catch (final NumberFormatException ex) {
logger.debug("NODE {}: commandPollDelay ({}) cannot be set - using default", nodeId, configurationParameter.getValue().toString());
}
if (commandPollDelay != 0 && commandPollDelay < REPOLL_PERIOD_MIN) {
commandPollDelay = REPOLL_PERIOD_MIN;
}
if (commandPollDelay > REPOLL_PERIOD_MAX) {
commandPollDelay = REPOLL_PERIOD_MAX;
}
valueObject = new BigDecimal(commandPollDelay);
}
break;
case "action":
if ("failed".equals(cfg[1]) && valueObject instanceof Boolean && ((Boolean) valueObject) == true) {
controllerHandler.replaceFailedNode(nodeId);
controllerHandler.checkNodeFailed(nodeId);
}
if ("remove".equals(cfg[1]) && valueObject instanceof Boolean && ((Boolean) valueObject) == true) {
controllerHandler.removeFailedNode(nodeId);
}
if ("reinit".equals(cfg[1]) && valueObject instanceof Boolean && ((Boolean) valueObject) == true) {
logger.debug("NODE {}: Re-initialising node!", nodeId);
// Delete the saved XML
ZWaveNodeSerializer nodeSerializer = new ZWaveNodeSerializer();
nodeSerializer.deleteNode(node.getHomeId(), nodeId);
controllerHandler.reinitialiseNode(nodeId);
}
if ("heal".equals(cfg[1]) && valueObject instanceof Boolean && ((Boolean) valueObject) == true) {
logger.debug("NODE {}: Starting heal on node!", nodeId);
controllerHandler.healNode(nodeId);
}
// Don't save the value
valueObject = false;
break;
default:
logger.debug("NODE {}: Configuration invalid {}", nodeId, configurationParameter.getKey());
}
configuration.put(configurationParameter.getKey(), valueObject);
}
// Persist changes
updateConfiguration(configuration);
// so handle it here once we've processed all configuration
if (wakeupInterval != null || wakeupNode != null) {
ZWaveWakeUpCommandClass wakeupCommandClass = (ZWaveWakeUpCommandClass) node.getCommandClass(CommandClass.COMMAND_CLASS_WAKE_UP);
if (wakeupCommandClass == null) {
logger.debug("NODE {}: Error getting wakeupCommandClass", nodeId);
} else {
// Handle the situation where there is only part of the data defined in this update
if (wakeupInterval == null) {
// First try using the current wakeup interval from the thing config
final BigDecimal cfgInterval = (BigDecimal) getConfig().get(ZWaveBindingConstants.CONFIGURATION_WAKEUPINTERVAL);
if (cfgInterval != null) {
wakeupInterval = cfgInterval.intValue();
}
// Then try the existing value from the command class
if (wakeupInterval == null) {
wakeupInterval = wakeupCommandClass.getInterval();
}
// Then try system default
if (wakeupInterval == 0) {
wakeupInterval = controllerHandler.getDefaultWakeupPeriod();
}
// Then try device default
if (wakeupInterval == 0) {
wakeupInterval = wakeupCommandClass.getDefaultInterval();
}
// If all else fails, use 1 hour!
if (wakeupInterval == 0) {
wakeupInterval = 3600;
}
logger.debug("NODE {}: Wakeup interval not specified, using {}", nodeId, wakeupInterval);
}
if (wakeupNode == null) {
// First try using the current wakeup node from the thing config
final BigDecimal cfgNode = (BigDecimal) getConfig().get(ZWaveBindingConstants.CONFIGURATION_WAKEUPNODE);
if (cfgNode != null) {
wakeupNode = cfgNode.intValue();
}
// Then try the existing value from the command class
if (wakeupNode == null) {
wakeupNode = wakeupCommandClass.getTargetNodeId();
}
// Then just set it to our node ID
if (wakeupNode == 0) {
wakeupNode = controllerHandler.getOwnNodeId();
}
logger.debug("NODE {}: Wakeup node not specified, using {}", nodeId, wakeupNode);
}
// Set the wake-up interval
node.sendMessage(wakeupCommandClass.setInterval(wakeupNode, wakeupInterval));
// And request a read-back
node.sendMessage(wakeupCommandClass.getIntervalMessage());
}
}
}
Aggregations