use of org.openhab.binding.zwave.internal.protocol.ZWaveNode in project openhab1-addons by openhab.
the class ZWaveNetworkMonitor method execute.
/**
* The execute method is called periodically from the binding. It is the
* main entry point for the network monitor class. It will (optionally)
* perform a network heal at a specified time.
*/
public void execute() {
// Don't start the next node if there's a queue
if (zController.getSendQueueLength() > 1) {
logger.debug("Network Monitor: Queue length is {} - deferring network monitor functions.", zController.getSendQueueLength());
return;
}
if (pingNodeTime < System.currentTimeMillis()) {
// Update the time and send a ping...
pingNodeTime = System.currentTimeMillis() + pollPeriod;
// Find the node that we haven't communicated with for the longest time
ZWaveNode oldestNode = null;
for (ZWaveNode node : zController.getNodes()) {
// Ignore the controller and nodes that aren't listening
if (node.getNodeId() == zController.getOwnNodeId() || node.isListening() == false) {
continue;
}
// This avoids the situation where we only poll a dead node if we use the received time!
if (oldestNode == null || oldestNode.getLastSent() == null) {
oldestNode = node;
} else if (node.getLastSent() == null || node.getLastSent().getTime() < oldestNode.getLastSent().getTime()) {
oldestNode = node;
}
}
// We now have the oldest node that we've sent to - ping it!
if (oldestNode != null) {
logger.debug("NODE {}: Sending periodic PING.", oldestNode.getNodeId());
// Reset the resend count - also resets the lastUpdate timer
oldestNode.resetResendCount();
ZWaveNoOperationCommandClass zwaveCommandClass = (ZWaveNoOperationCommandClass) oldestNode.getCommandClass(CommandClass.NO_OPERATION);
if (zwaveCommandClass != null) {
zController.sendData(zwaveCommandClass.getNoOperationMessage());
}
} else {
logger.debug("Network Monitor: No nodes to ping!");
}
// period
return;
}
// Check if it's time to do another 'nightly' heal
if (networkHealNightlyTime < System.currentTimeMillis()) {
rescheduleHeal();
networkHealNightlyTime = calculateNextHeal();
}
// Check to see if there's been a timeout during the heal process
if (networkHealNextTime > System.currentTimeMillis()) {
return;
}
// timeout
for (Map.Entry<Integer, HealNode> entry : healNodes.entrySet()) {
HealNode node = entry.getValue();
if (node.state != HealState.WAITING && node.state != HealState.FAILED && node.state != HealState.DONE && node.listening == true) {
nextHealStage(node);
return;
}
}
// No nodes are currently healing - run the next node
for (Map.Entry<Integer, HealNode> entry : healNodes.entrySet()) {
HealNode node = entry.getValue();
// This should be triggered by a WAKEUP
if (node.state == HealState.WAITING && node.listening == true) {
nextHealStage(node);
return;
}
}
// There's nothing more to do
networkHealNextTime = networkHealNightlyTime;
}
use of org.openhab.binding.zwave.internal.protocol.ZWaveNode in project openhab1-addons by openhab.
the class ZWaveNetworkMonitor method startNodeHeal.
/**
* Perform an immediate heal on the specified node
*
* @param nodeId
* Node to perform the heal on
* @return true if the heal is scheduled
*/
public boolean startNodeHeal(int nodeId) {
ZWaveNode node = zController.getNode(nodeId);
if (node == null) {
logger.error("NODE {}: Heal node - can't be found.", nodeId);
return false;
}
// If so, don't start it again!
if (isNodeHealing(nodeId)) {
logger.debug("NODE {}: Node is already healing.", node.getNodeId());
return false;
}
HealNode heal = new HealNode();
heal.node = node;
heal.nodeId = nodeId;
heal.retryCnt = 0;
heal.routeList = null;
heal.state = HealState.WAITING;
heal.lastChange = Calendar.getInstance().getTime();
// Find out if this is a listening device
if (node.isListening()) {
heal.listening = true;
} else {
heal.listening = false;
}
healNodes.put(nodeId, heal);
logger.debug("NODE {}: Starting heal", nodeId);
// Start the first heal next time around the loop
networkHealNextTime = 0;
return true;
}
use of org.openhab.binding.zwave.internal.protocol.ZWaveNode in project openhab1-addons by openhab.
the class ZWaveNetworkMonitor method nextHealStage.
/**
* Perform the next step in the heal process. This function also handles the
* retries. Each time through the loop it increments the retry counter. If
* the max retries is exceeded then the failed state is saved and we return
* to allow other nodes to continue.
*
* @param healing
* The node on which to perform the heal
*/
private void nextHealStage(HealNode healing) {
// Don't do anything if it's failed already
if (healing.state == HealState.FAILED) {
return;
}
healing.lastChange = Calendar.getInstance().getTime();
// Set the ping time into the future.
// This holds off the routine ping when there's a heal in progress
// to avoid congestion and false timeouts.
pingNodeTime = System.currentTimeMillis() + HEAL_TIMEOUT_PERIOD + 20000;
// Set the timeout
networkHealNextTime = System.currentTimeMillis() + HEAL_TIMEOUT_PERIOD;
// Only do something if the node is awake!
ZWaveNode node = zController.getNode(healing.nodeId);
if (node != null) {
ZWaveWakeUpCommandClass wakeupCommandClass = (ZWaveWakeUpCommandClass) node.getCommandClass(CommandClass.WAKE_UP);
if (wakeupCommandClass != null && wakeupCommandClass.isAwake() == false) {
// Device is asleep - don't do anything now!
logger.debug("NODE {}: Node is asleep. Defer heal until it's awake", healing.nodeId);
return;
}
}
// Handle retries
healing.retryCnt++;
if (healing.retryCnt >= HEAL_MAX_RETRIES) {
logger.debug("NODE {}: Maximum retries in state {}", healing.nodeId, healing.state);
// continue with the heal than to abort here.
if (healing.state == HealState.UPDATENEIGHBORS) {
healing.state = healing.stateNext;
healing.retryCnt = 0;
logger.debug("NODE {}: Heal - continuing to state {}", healing.nodeId, healing.stateNext);
} else {
logger.debug("NODE {}: Network heal has exceeded maximum retries!", healing.nodeId);
healing.failState = healing.state;
healing.state = HealState.FAILED;
// Save the XML file. This serialises the data we've just updated
// (neighbors etc)
healing.node.setHealState(this.getNodeState(healing.node.getNodeId()));
ZWaveNodeSerializer nodeSerializer = new ZWaveNodeSerializer();
nodeSerializer.SerializeNode(healing.node);
return;
}
}
// Set the timeout
networkHealNextTime = System.currentTimeMillis() + HEAL_TIMEOUT_PERIOD;
switch(healing.state) {
case WAITING:
// Log what we're up to...
logger.debug("NODE {}: NETWORK HEAL - STARTING", healing.nodeId);
// Reset the resend count.
// This also resets the time so that we cycle through all the nodes
healing.node.resetResendCount();
healing.state = HealState.PING;
case PING:
// Log what we're up to...
logger.debug("NODE {}: NETWORK HEAL - {}", healing.nodeId, healing.state);
if (healing.nodeId != zController.getOwnNodeId()) {
healing.state = HealState.PING;
ZWaveNoOperationCommandClass zwaveCommandClass = (ZWaveNoOperationCommandClass) healing.node.getCommandClass(CommandClass.NO_OPERATION);
if (zwaveCommandClass != null) {
zController.sendData(zwaveCommandClass.getNoOperationMessage());
healing.stateNext = HealState.SETSUCROUTE;
break;
}
}
healing.state = HealState.SETSUCROUTE;
case SETSUCROUTE:
// Log what we're up to...
logger.debug("NODE {}: NETWORK HEAL - {}", healing.nodeId, healing.state);
// Only set the route if this is not the controller and there is an SUC in the network
if (healing.nodeId != zController.getOwnNodeId() && zController.getSucId() != 0) {
// Update the route to the controller
logger.debug("NODE {}: Heal is setting SUC route.", healing.nodeId);
healing.event = ZWaveNetworkEvent.Type.AssignSucReturnRoute;
healing.stateNext = HealState.UPDATENEIGHBORS;
zController.requestAssignSucReturnRoute(healing.nodeId);
break;
}
healing.state = HealState.UPDATENEIGHBORS;
case UPDATENEIGHBORS:
// Log what we're up to...
logger.debug("NODE {}: NETWORK HEAL - {}", healing.nodeId, healing.state);
healing.event = ZWaveNetworkEvent.Type.NodeNeighborUpdate;
healing.stateNext = HealState.GETASSOCIATIONS;
zController.requestNodeNeighborUpdate(healing.nodeId);
break;
case GETASSOCIATIONS:
// Log what we're up to...
logger.debug("NODE {}: NETWORK HEAL - {}", healing.nodeId, healing.state);
// Check if this node supports associations
ZWaveAssociationCommandClass associationCommandClass = (ZWaveAssociationCommandClass) healing.node.getCommandClass(CommandClass.ASSOCIATION);
if (associationCommandClass != null) {
logger.debug("NODE {}: Heal is requesting device associations.", healing.nodeId);
healing.stateNext = HealState.UPDATEROUTES;
healing.event = ZWaveNetworkEvent.Type.AssociationUpdate;
associationCommandClass.getAllAssociations();
break;
}
healing.stateNext = HealState.UPDATEROUTES;
case UPDATEROUTES:
// Log what we're up to...
logger.debug("NODE {}: NETWORK HEAL - {}", healing.nodeId, healing.state);
// Get the list of routes for this node
healing.routeList = healing.node.getRoutingList();
if (healing.routeList != null && healing.routeList.size() != 0) {
// Delete all the return routes for the node
logger.debug("NODE {}: Heal is deleting routes.", healing.nodeId);
healing.event = ZWaveNetworkEvent.Type.DeleteReturnRoute;
healing.stateNext = HealState.UPDATEROUTESNEXT;
zController.requestDeleteAllReturnRoutes(healing.nodeId);
break;
}
healing.stateNext = HealState.UPDATEROUTESNEXT;
case UPDATEROUTESNEXT:
// Log what we're up to...
logger.debug("NODE {}: NETWORK HEAL - {}", healing.nodeId, healing.state);
if (healing.routeList != null && healing.routeList.size() != 0) {
// Loop through all the nodes and set the return route
logger.debug("NODE {}: Adding return route to {}", healing.nodeId, healing.routeList.get(0));
healing.stateNext = HealState.GETNEIGHBORS;
healing.event = ZWaveNetworkEvent.Type.AssignReturnRoute;
zController.requestAssignReturnRoute(healing.nodeId, healing.routeList.get(0));
break;
}
healing.stateNext = HealState.GETNEIGHBORS;
case GETNEIGHBORS:
// Log what we're up to...
logger.debug("NODE {}: NETWORK HEAL - {}", healing.nodeId, healing.state);
healing.event = ZWaveNetworkEvent.Type.NodeRoutingInfo;
healing.stateNext = HealState.SAVE;
logger.debug("NODE {}: Heal is requesting node neighbor info.", healing.nodeId);
zController.requestNodeRoutingInfo(healing.nodeId);
break;
case SAVE:
// Log what we're up to...
logger.debug("NODE {}: NETWORK HEAL - {}", healing.nodeId, healing.state);
healing.state = HealState.DONE;
networkHealNextTime = System.currentTimeMillis() + HEAL_DELAY_PERIOD;
// Save the XML file. This serialises the data we've just updated
// (neighbors etc)
healing.node.setHealState(this.getNodeState(healing.node.getNodeId()));
ZWaveNodeSerializer nodeSerializer = new ZWaveNodeSerializer();
nodeSerializer.SerializeNode(healing.node);
break;
default:
break;
}
healing.node.setHealState(this.getNodeState(healing.node.getNodeId()));
}
use of org.openhab.binding.zwave.internal.protocol.ZWaveNode in project openhab1-addons by openhab.
the class ZWaveConfiguration method doSet.
@Override
public void doSet(String domain, String value) {
logger.debug("doSet domain '{}' to '{}'", domain, value);
String[] splitDomain = domain.split("/");
// If the controller isn't ready, then ignore any requests
if (zController.isConnected() == false) {
logger.debug("Controller not ready - Ignoring request to '{}'", domain);
return;
}
// There must be at least 2 components to the domain
if (splitDomain.length < 2) {
logger.error("Error malformed domain in doSet '{}'", domain);
return;
}
if (splitDomain[0].equals("nodes")) {
int nodeId = Integer.parseInt(splitDomain[1].substring(4));
ZWaveNode node = zController.getNode(nodeId);
if (node == null) {
logger.error("Error finding node in doSet '{}'", domain);
return;
}
// TODO: Should we check that the node is finished initialising
ZWaveProductDatabase database = new ZWaveProductDatabase();
if (database.FindProduct(node.getManufacturer(), node.getDeviceType(), node.getDeviceId(), node.getApplicationVersion()) == false) {
logger.error("NODE {}: Error in doSet - no database found", nodeId);
return;
}
if (splitDomain.length == 3) {
if (splitDomain[2].equals("Name")) {
node.setName(value);
}
if (splitDomain[2].equals("Location")) {
node.setLocation(value);
}
if (splitDomain[2].equals("SwitchAll")) {
ZWaveSwitchAllCommandClass switchAllCommandClass = (ZWaveSwitchAllCommandClass) node.getCommandClass(CommandClass.SWITCH_ALL);
if (switchAllCommandClass == null) {
logger.error("NODE {}: Error getting switchAllCommandClass in doSet", nodeId);
return;
}
// Set the switch all mode
int mode = Integer.parseInt(value);
PendingCfg.Add(ZWaveSwitchAllCommandClass.CommandClass.SWITCH_ALL.getKey(), node.getNodeId(), 0, mode);
SerialMessage msg = switchAllCommandClass.setValueMessage(mode);
this.zController.sendData(msg);
// And request a read-back
this.zController.sendData(switchAllCommandClass.getValueMessage());
}
// Write the node to disk
ZWaveNodeSerializer nodeSerializer = new ZWaveNodeSerializer();
nodeSerializer.SerializeNode(node);
} else if (splitDomain.length == 4) {
if (splitDomain[2].equals("parameters")) {
ZWaveConfigurationCommandClass configurationCommandClass = (ZWaveConfigurationCommandClass) node.getCommandClass(CommandClass.CONFIGURATION);
if (configurationCommandClass == null) {
logger.error("NODE {}: Error getting configurationCommandClass in doSet", nodeId);
return;
}
int paramIndex = Integer.parseInt(splitDomain[3].substring(13));
List<ZWaveDbConfigurationParameter> configList = database.getProductConfigParameters();
// Get the size
int size = 1;
for (ZWaveDbConfigurationParameter parameter : configList) {
if (parameter.Index == paramIndex) {
size = parameter.Size;
break;
}
}
logger.debug("Set parameter index '{}' to '{}'", paramIndex, value);
PendingCfg.Add(ZWaveCommandClass.CommandClass.CONFIGURATION.getKey(), nodeId, paramIndex, Integer.valueOf(value));
ConfigurationParameter configurationParameter = new ConfigurationParameter(paramIndex, Integer.valueOf(value), size);
// Set the parameter
this.zController.sendData(configurationCommandClass.setConfigMessage(configurationParameter));
// And request a read-back
this.zController.sendData(configurationCommandClass.getConfigMessage(paramIndex));
}
if (splitDomain[2].equals("wakeup")) {
ZWaveWakeUpCommandClass wakeupCommandClass = (ZWaveWakeUpCommandClass) node.getCommandClass(CommandClass.WAKE_UP);
if (wakeupCommandClass == null) {
logger.error("NODE {}: Error getting wakeupCommandClass in doSet", nodeId);
return;
}
logger.debug("NODE {}: Set wakeup interval to '{}'", nodeId, value);
// Add this as a pending transaction
PendingCfg.Add(ZWaveCommandClass.CommandClass.WAKE_UP.getKey(), node.getNodeId(), Integer.parseInt(value));
// Set the wake-up interval
this.zController.sendData(wakeupCommandClass.setInterval(Integer.parseInt(value)));
// And request a read-back
this.zController.sendData(wakeupCommandClass.getIntervalMessage());
}
if (splitDomain[2].equals("controller")) {
if (splitDomain[3].equals("Type")) {
ZWaveDeviceType type = ZWaveDeviceType.fromString(value);
logger.error("NODE {}: Setting controller type to {}", nodeId, type.toString());
// ZW_EnableSUC and ZW_SetSUCNodeID
}
}
} else if (splitDomain.length == 5) {
if (splitDomain[2].equals("associations")) {
ZWaveAssociationCommandClass associationCommandClass = (ZWaveAssociationCommandClass) node.getCommandClass(CommandClass.ASSOCIATION);
if (associationCommandClass == null) {
logger.error("NODE {}: Error getting associationCommandClass in doSet", nodeId);
return;
}
int assocId = Integer.parseInt(splitDomain[3].substring(11));
int assocArg = Integer.parseInt(splitDomain[4].substring(4));
if (value.equalsIgnoreCase("true")) {
PendingCfg.Add(ZWaveCommandClass.CommandClass.ASSOCIATION.getKey(), nodeId, assocId, assocArg, 1);
logger.debug("Add association index '{}' to '{}'", assocId, assocArg);
this.zController.sendData(associationCommandClass.setAssociationMessage(assocId, assocArg));
} else {
PendingCfg.Add(ZWaveCommandClass.CommandClass.ASSOCIATION.getKey(), nodeId, assocId, assocArg, 0);
logger.debug("Remove association index '{}' to '{}'", assocId, assocArg);
this.zController.sendData(associationCommandClass.removeAssociationMessage(assocId, assocArg));
}
// Request an update to the group
this.zController.sendData(associationCommandClass.getAssociationMessage(assocId));
// So, let's start a network heal - just for this node right now
if (networkMonitor != null) {
networkMonitor.startNodeHeal(nodeId);
}
}
}
}
}
use of org.openhab.binding.zwave.internal.protocol.ZWaveNode in project openhab1-addons by openhab.
the class ZWaveConfiguration method doAction.
@Override
public void doAction(String domain, String action) {
logger.trace("doAction domain '{}' to '{}'", domain, action);
String[] splitDomain = domain.split("/");
// There must be at least 2 components to the domain
if (splitDomain.length < 2) {
logger.error("Error malformed domain in doAction '{}'", domain);
return;
}
// Process Controller Reset requests even if the controller isn't initialised
if (splitDomain[0].equals("binding") && splitDomain[1].equals("network")) {
if (action.equals("SoftReset")) {
zController.requestSoftReset();
} else if (action.equals("HardReset")) {
zController.requestHardReset();
}
}
// If the controller isn't ready, then ignore any further requests
if (zController.isConnected() == false) {
logger.debug("Controller not ready - Ignoring request to '{}'", domain);
return;
}
if (splitDomain[0].equals("binding")) {
if (splitDomain[1].equals("network")) {
if (action.equals("Heal")) {
if (networkMonitor != null) {
networkMonitor.rescheduleHeal();
}
}
if (action.equals("Include") || action.equals("Exclude")) {
// Only do include/exclude if it's not already in progress
if (inclusion == false && exclusion == false) {
if (action.equals("Include")) {
inclusion = true;
zController.requestAddNodesStart();
setInclusionTimer();
}
if (action.equals("Exclude")) {
exclusion = true;
zController.requestRemoveNodesStart();
setInclusionTimer();
}
} else {
logger.debug("Exclusion/Inclusion already in progress.");
}
}
}
}
if (splitDomain[0].equals("nodes")) {
int nodeId = Integer.parseInt(splitDomain[1].substring(4));
// Get the node - if it exists
ZWaveNode node = zController.getNode(nodeId);
if (node == null) {
logger.error("NODE {}: Error finding node in doAction", nodeId);
return;
}
if (splitDomain.length == 2) {
if (action.equals("Heal")) {
logger.debug("NODE {}: Heal node", nodeId);
if (networkMonitor != null) {
networkMonitor.startNodeHeal(nodeId);
}
}
if (action.equals("Save")) {
logger.debug("NODE {}: Saving node", nodeId);
// Write the node to disk
ZWaveNodeSerializer nodeSerializer = new ZWaveNodeSerializer();
nodeSerializer.SerializeNode(node);
}
if (action.equals("Initialise")) {
logger.debug("NODE {}: re-initialising node", nodeId);
// Delete the saved XML
ZWaveNodeSerializer nodeSerializer = new ZWaveNodeSerializer();
nodeSerializer.DeleteNode(nodeId);
this.zController.reinitialiseNode(nodeId);
}
if (action.equals("Delete")) {
logger.debug("NODE {}: Delete node", nodeId);
this.zController.requestRemoveFailedNode(nodeId);
}
// in the domain array
return;
}
if (splitDomain[2].equals("parameters")) {
ZWaveConfigurationCommandClass configurationCommandClass = (ZWaveConfigurationCommandClass) node.getCommandClass(CommandClass.CONFIGURATION);
if (configurationCommandClass == null) {
return;
}
if (action.equals("Refresh")) {
logger.debug("NODE {}: Refresh parameters", nodeId);
ZWaveProductDatabase database = new ZWaveProductDatabase();
if (database.FindProduct(node.getManufacturer(), node.getDeviceType(), node.getDeviceId(), node.getApplicationVersion()) == false) {
return;
}
List<ZWaveDbConfigurationParameter> configList = database.getProductConfigParameters();
// Request all parameters for this node
for (ZWaveDbConfigurationParameter parameter : configList) {
this.zController.sendData(configurationCommandClass.getConfigMessage(parameter.Index));
}
}
}
if (splitDomain[2].equals("wakeup")) {
if (action.equals("Refresh")) {
// Only update if we support the wakeup class
ZWaveWakeUpCommandClass wakeupCommandClass = (ZWaveWakeUpCommandClass) node.getCommandClass(CommandClass.WAKE_UP);
if (wakeupCommandClass == null) {
return;
}
logger.debug("NODE {}: Refresh wakeup capabilities", nodeId);
// Request the wakeup interval for this node
this.zController.sendData(wakeupCommandClass.getIntervalMessage());
// Request the wakeup parameters for this node
this.zController.sendData(wakeupCommandClass.getIntervalCapabilitiesMessage());
}
}
if (splitDomain[2].equals("neighbors")) {
if (action.equals("Refresh")) {
// this.zController.requestNodeNeighborUpdate(nodeId);
// .requestNodeNeighborUpdate(nodeId);
this.zController.requestNodeRoutingInfo(nodeId);
}
}
if (splitDomain[2].equals("associations")) {
if (action.equals("Refresh")) {
// Make sure the association class is supported
ZWaveAssociationCommandClass associationCommandClass = (ZWaveAssociationCommandClass) node.getCommandClass(CommandClass.ASSOCIATION);
if (associationCommandClass == null) {
return;
}
logger.debug("NODE {}: Refresh associations", nodeId);
ZWaveProductDatabase database = new ZWaveProductDatabase();
if (database.FindProduct(node.getManufacturer(), node.getDeviceType(), node.getDeviceId(), node.getApplicationVersion()) == false) {
logger.error("NODE {}: Error in doAction - no database found", nodeId);
return;
}
if (splitDomain.length == 3) {
// Request all groups for this node
associationCommandClass.getAllAssociations();
} else if (splitDomain.length == 4) {
// Request a single group
int nodeArg = Integer.parseInt(splitDomain[3].substring(11));
this.zController.sendData(associationCommandClass.getAssociationMessage(nodeArg));
}
}
}
}
}
Aggregations