On Feb 9, 2014 9:32 PM, "Ben Jones" <notifications@github.com> wrote:

> In
> bundles/binding/org.openhab.binding.zwave/src/main/java/org/openhab/binding/zwave/internal/protocol/ZWaveController.java:
>
> > -				if(data == 0xef )  {
> > -					// TODO: Implement control command classes
> > -					break;
> > +			if(node.getNodeStage() == NodeStage.DONE) {
> > +				// 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("Application update request, requesting node state.");
> > +
> > +				// reset and advance node stage to trigger the value request messages
> > +				node.setNodeStage(NodeStage.DYNAMIC);
> > +				node.advanceNodeStage(NodeStage.DONE);
> > +				
> > +				// make sure we've made it to the done stage, for some reason DYNAMIC
> > +				// has to be passed through twice.
> > +				if(node.getNodeStage() == NodeStage.DYNAMIC)
>
> I think the binding is waiting for a response to the 'query' messages -
> i.e. a query is sent for the current dynamic value, and it is not until the
> binding receives a response can it safely move onto the next stage (which
> in this case is DONE).
>
> Can you remove lines 340-343 and see if things still work?
>
> --
> Reply to this email directly or view it on GitHub<https://github.com/openhab/openhab/pull/840/files#r9574013>
> .
>
Ben, I've tried it without that bit and it only works half the time. I've
done a fair amount of testing and looking over the code and the issue is in
the code below from the ZWaveNodeStageAdvancer.java file. The
queriesPending variable must be set to -1 for any messages to be sent. If
it is, the block sets the queriesPending to zero, then searches for command
classes that are appropriate to send requests for, and then sends out
requests for updates. The issue is that after the if statement checking
queriesPending for a value of -1, there is another statement that checks if
the queriesPending is greater than zero. If it is, because a query was sent
out, the switch statement breaks and the rest of the method does not
execute until the method is called a subsequent time. When it is called
again, it enters the switch statement with a queriesPending counter that is
not -1, so it skips the whole block of code that would send a message and
goes directly to the test of queriesPending greater than zero, then
decrement. Once the method has been called enough times to decrement the
queriesPending counter back down to zero, the counter is reset to -1 to
allow the process to repeat. I really think this is a bug in the
ZWaveNodeStageAdvancer class but I'm not familiar enough with the binding's
architecture to be certain. That is why I just added the second call to
advanceNodeStage in the ZWaveController class, rather than change the
behaviour of the NodeStageAdvancer class.

Also, during my testing I confirmed that the initialization process is
calling advanceNodeStage twice for the DYNAMIC stage. Which is happening
completely separate from the code involved in the patch.

Did that make sense, or am I just confused about how it is working?

case DYNAMIC:
if (queriesPending == -1) {
queriesPending = 0;
for (ZWaveCommandClass zwaveCommandClass : this.node.getCommandClasses()) {
logger.trace("NODE {}: Inspecting command class {}", this.node.getNodeId(),
zwaveCommandClass.getCommandClass().getLabel());
if (zwaveCommandClass instanceof ZWaveCommandClassDynamicState) {
logger.debug("NODE {}: Found dynamic state command class {}",
this.node.getNodeId(), zwaveCommandClass.getCommandClass()
.getLabel());
ZWaveCommandClassDynamicState zdds = (ZWaveCommandClassDynamicState)
zwaveCommandClass;
int instances = zwaveCommandClass.getInstances();
if (instances == 0) {
Collection<SerialMessage> dynamicQueries = zdds.getDynamicValues();
for (SerialMessage serialMessage : dynamicQueries) {
this.controller.sendData(serialMessage);
queriesPending++;
}
} else {
for (int i = 1; i <= instances; i++) {
Collection<SerialMessage> dynamicQueries = zdds.getDynamicValues();
for (SerialMessage serialMessage : dynamicQueries) {
this.controller
.sendData(this.node.encapsulate(serialMessage, zwaveCommandClass, i));
queriesPending++;
}
}
}
} else if (zwaveCommandClass instanceof ZWaveMultiInstanceCommandClass) {
ZWaveMultiInstanceCommandClass multiInstanceCommandClass =
(ZWaveMultiInstanceCommandClass) zwaveCommandClass;
for (ZWaveEndpoint endpoint : multiInstanceCommandClass.getEndpoints()) {
for (ZWaveCommandClass endpointCommandClass : endpoint.getCommandClasses())
{
logger.trace(String.format("NODE %d: Inspecting command class %s for
endpoint %d", this.node.getNodeId(), endpointCommandClass
.getCommandClass().getLabel(), endpoint.getEndpointId()));
if (endpointCommandClass instanceof ZWaveCommandClassDynamicState) {
logger.debug("NODE {}: Found dynamic state command class {}",
this.node.getNodeId(), endpointCommandClass
.getCommandClass().getLabel());
ZWaveCommandClassDynamicState zdds2 = (ZWaveCommandClassDynamicState)
endpointCommandClass;
Collection<SerialMessage> dynamicQueries = zdds2.getDynamicValues();
for (SerialMessage serialMessage : dynamicQueries) {
this.controller.sendData(this.node.encapsulate(serialMessage,
endpointCommandClass, endpoint.getEndpointId()));
queriesPending++;
}
}
}
}
}
}
}
if (queriesPending-- > 0) // there is still something to be
// initialized.
break;
logger.trace("NODE {}: Done getting dynamic values, proceeding to done node
stage.", this.node.getNodeId());
queriesPending = -1;

this.node.setNodeStage(NodeStage.DONE); // nothing
// more
// to
// do
// for
// this
// node.

nodeSerializer.SerializeNode(this.node);

initializationComplete = true;

if (this.node.isListening() || this.node.isFrequentlyListening())
return;

ZWaveWakeUpCommandClass wakeup = (ZWaveWakeUpCommandClass)
this.node.getCommandClass(CommandClass.WAKE_UP);

if (wakeup == null)
return;

logger.debug("NODE {}: is a battery operated device. Tell it to go to
sleep.", this.node.getNodeId());
this.controller.sendData(wakeup.getNoMoreInformationMessage());
break;