Skip to content

Commit 577fff9

Browse files
authored
Ota upgrade updates (#1475)
* Updates * In progress updates working with battery device
1 parent 891d209 commit 577fff9

5 files changed

Lines changed: 89 additions & 31 deletions

File tree

com.zsmartsystems.zigbee.console/src/main/java/com/zsmartsystems/zigbee/console/ZigBeeConsoleOtaUpgradeCommand.java

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import com.zsmartsystems.zigbee.app.otaserver.ZclOtaUpgradeServer;
2323
import com.zsmartsystems.zigbee.app.otaserver.ZigBeeOtaFile;
2424
import com.zsmartsystems.zigbee.zcl.clusters.ZclOtaUpgradeCluster;
25+
import com.zsmartsystems.zigbee.zcl.clusters.otaupgrade.ImageNotifyCommand;
2526

2627
/**
2728
*
@@ -70,6 +71,12 @@ public void process(ZigBeeNetworkManager networkManager, String[] args, PrintStr
7071
}
7172
cmdNodeState(networkManager, args[2], out);
7273
break;
74+
case "NOTIFY":
75+
if (args.length < 3) {
76+
throw new IllegalArgumentException("Invalid number of arguments: Endpoint required.");
77+
}
78+
cmdOtaKick(networkManager, args[2], out);
79+
break;
7380
case "START":
7481
if (args.length < 4) {
7582
throw new IllegalArgumentException("Invalid number of arguments: Endpoint and Filename required.");
@@ -122,12 +129,16 @@ private void cmdDisplayAllNodes(ZigBeeNetworkManager networkManager, PrintStream
122129
return;
123130
}
124131

125-
out.println("Address IEEE Address State ");
132+
out.println("Address IEEE Address State % Last Request");
126133
for (ZigBeeEndpoint endpoint : applications.values()) {
127134
ZclOtaUpgradeServer otaServer = (ZclOtaUpgradeServer) endpoint
128135
.getApplication(ZclOtaUpgradeCluster.CLUSTER_ID);
129-
out.println(String.format("%-9s %s %-8s", endpoint.getEndpointAddress(), endpoint.getIeeeAddress(),
130-
otaServer.getServerStatus()));
136+
out.println(String.format("%-9s %s %-31s %3s %s", endpoint.getEndpointAddress(),
137+
endpoint.getIeeeAddress(),
138+
otaServer.getServerStatus(),
139+
otaServer.getPercentageComplete() == null ? " "
140+
: String.format("%3d", otaServer.getPercentageComplete()),
141+
otaServer.getLastImageRequestTime() == null ? "NEVER" : otaServer.getLastImageRequestTime()));
131142
}
132143
}
133144

@@ -173,6 +184,21 @@ private void cmdDisplayFileInfo(String filename, PrintStream out) {
173184
out.println("OTA File: " + otaFile);
174185
}
175186

187+
private void cmdOtaKick(ZigBeeNetworkManager networkManager, String endpointString,
188+
PrintStream out) {
189+
final ZigBeeEndpoint endpoint = getEndpoint(networkManager, endpointString);
190+
191+
ZclOtaUpgradeCluster cluster = (ZclOtaUpgradeCluster) endpoint
192+
.getOutputCluster(ZclOtaUpgradeCluster.CLUSTER_ID);
193+
if (cluster == null) {
194+
throw new IllegalArgumentException("OTA Server not supported by " + endpoint.getEndpointAddress() + "");
195+
}
196+
197+
cluster.sendCommand(new ImageNotifyCommand(0, 0, 0, 0, 0));
198+
199+
out.println("OTA notify sent to " + endpoint.getEndpointAddress() + "");
200+
}
201+
176202
private void cmdOtaStart(ZigBeeNetworkManager networkManager, String endpointString, String filename,
177203
PrintStream out) {
178204
final ZigBeeEndpoint endpoint = getEndpoint(networkManager, endpointString);

com.zsmartsystems.zigbee/src/main/java/com/zsmartsystems/zigbee/app/otaserver/ZclOtaUpgradeServer.java

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import java.util.ArrayList;
1111
import java.util.Arrays;
1212
import java.util.Collections;
13+
import java.util.Date;
1314
import java.util.List;
1415
import java.util.Random;
1516
import java.util.concurrent.CountDownLatch;
@@ -131,6 +132,11 @@ public class ZclOtaUpgradeServer implements ZigBeeApplication, ZclCommandListene
131132
*/
132133
private ZigBeeOtaServerStatus status;
133134

135+
/**
136+
* The time of the last image update request
137+
*/
138+
private Date lastImageRequestTime = null;
139+
134140
/**
135141
* The parameter is part of Image Notify Command sent by the upgrade server. The parameter indicates
136142
* whether the client receiving Image Notify Command should send in Query Next Image Request
@@ -220,7 +226,7 @@ public class ZclOtaUpgradeServer implements ZigBeeApplication, ZclCommandListene
220226
/**
221227
* The sleep time before trying to request the current firmware version
222228
*/
223-
private static final long CURRENT_FW_VERSION_REQUEST_DELAY = 10000;
229+
private static final long CURRENT_FW_VERSION_REQUEST_DELAY = 1500;
224230

225231
/**
226232
* Field control value of 0x01 (bit 0 set) means that the client’s IEEE address is included in the payload. This
@@ -279,6 +285,24 @@ public ZigBeeOtaServerStatus getServerStatus() {
279285
return status;
280286
}
281287

288+
/**
289+
* Gets the time the last image update request was received
290+
*
291+
* @return the {@link Date} of the last received image request
292+
*/
293+
public Date getLastImageRequestTime() {
294+
return lastImageRequestTime;
295+
}
296+
297+
/**
298+
* Gets the percentage complete when an update is in progress. Returns null if not upgrade is in progress.
299+
*
300+
* @return the percentage complete, or null if not upgrade is in progress.
301+
*/
302+
public Integer getPercentageComplete() {
303+
return status == ZigBeeOtaServerStatus.OTA_UNINITIALISED ? null : percentComplete;
304+
}
305+
282306
/**
283307
* Cancels any upgrade transfers that are in progress and removes the current file. If a transfer is currently in
284308
* progress, then the listeners are notified.
@@ -455,7 +479,7 @@ public void run() {
455479
}
456480
ImageUpgradeStatus status = ImageUpgradeStatus.getStatus(statusValue);
457481
if (status != ImageUpgradeStatus.DOWNLOAD_COMPLETE
458-
&& status != ImageUpgradeStatus.WAITING_TO_UPGRADE) {
482+
&& status != ImageUpgradeStatus.WAITING_TO_UPGRADE && status != ImageUpgradeStatus.NORMAL) {
459483
// Client is not in correct state to end upgrade
460484
switch (status) {
461485
case COUNT_DOWN:
@@ -467,22 +491,22 @@ public void run() {
467491
case WAIT_FOR_MORE:
468492
updateStatus(ZigBeeOtaServerStatus.OTA_WAITING);
469493
break;
470-
case NORMAL:
471494
case UNKNOWN:
472495
default:
496+
logger.debug("{}: Unexpected remote transfer status {} - OTA failed.",
497+
status, cluster.getZigBeeAddress());
473498
updateStatus(ZigBeeOtaServerStatus.OTA_UPGRADE_FAILED);
474499
break;
475500
}
476501
return;
477502
}
478503

479-
updateStatus(ZigBeeOtaServerStatus.OTA_UPGRADE_FIRMWARE_RESTARTING);
480-
481504
UpgradeEndResponse upgradeEndResponse = new UpgradeEndResponse(otaFile.getManufacturerCode(),
482505
otaFile.getImageType(), otaFile.getFileVersion(), 0, 0);
506+
upgradeEndResponse.setDisableDefaultResponse(true);
483507

484508
// If we received a UpgradeEndCommand then send the UpgradeEndResponse as a response. Otherwise send
485-
// it as a commands
509+
// it as a command
486510
CommandResult response;
487511
if (command != null) {
488512
response = cluster.sendResponse(command, upgradeEndResponse).get();
@@ -491,9 +515,11 @@ public void run() {
491515
}
492516

493517
if (!(response.isSuccess() || response.isTimeout())) {
518+
logger.debug("{}: Failed to send UpgradeEnd - OTA failed.", cluster.getZigBeeAddress());
494519
updateStatus(ZigBeeOtaServerStatus.OTA_UPGRADE_FAILED);
495520
return;
496521
}
522+
updateStatus(ZigBeeOtaServerStatus.OTA_UPGRADE_FIRMWARE_RESTARTING);
497523

498524
// Attempt to get the current firmware version. As the device will be restarting, which could take
499525
// some time to complete, we retry this a few times.
@@ -526,6 +552,9 @@ public void run() {
526552
if (fileVersion.equals(otaFile.getFileVersion())) {
527553
updateStatus(ZigBeeOtaServerStatus.OTA_UPGRADE_COMPLETE);
528554
return;
555+
} else {
556+
updateStatus(ZigBeeOtaServerStatus.OTA_UPGRADE_FAILED);
557+
return;
529558
}
530559
} else if (attributesResponse.getRecords().get(0)
531560
.getStatus() == ZclStatus.UNSUPPORTED_ATTRIBUTE) {
@@ -695,6 +724,8 @@ public void run() {
695724
* @return true if the handler has, or will send a response to this command
696725
*/
697726
private boolean handleQueryNextImageCommand(QueryNextImageCommand command) {
727+
lastImageRequestTime = new Date();
728+
698729
if (otaFile == null) {
699730
logger.debug("{} OTA Server: No file set in QueryNextImageCommand.",
700731
cluster.getZigBeeAddress());
@@ -756,7 +787,7 @@ private boolean handleQueryNextImageCommand(QueryNextImageCommand command) {
756787
}
757788

758789
// Update the state as we're starting
759-
updateStatus(ZigBeeOtaServerStatus.OTA_TRANSFER_IN_PROGRESS);
790+
updateStatus(ZigBeeOtaServerStatus.OTA_STARTED);
760791
startTransferTimer();
761792

762793
cluster.sendResponse(command, new QueryNextImageResponse(
@@ -766,6 +797,8 @@ private boolean handleQueryNextImageCommand(QueryNextImageCommand command) {
766797
otaFile.getFileVersion(),
767798
otaFile.getImageSize()));
768799

800+
updateStatus(ZigBeeOtaServerStatus.OTA_TRANSFER_IN_PROGRESS);
801+
769802
return true;
770803
}
771804

@@ -894,7 +927,15 @@ private boolean handleUpgradeEndCommand(UpgradeEndCommand command) {
894927
&& status != ZigBeeOtaServerStatus.OTA_TRANSFER_COMPLETE) {
895928
logger.debug("{} OTA Error: Invalid server state {} when handling UpgradeEndCommand.",
896929
cluster.getZigBeeAddress(), status);
897-
cluster.sendDefaultResponse(command, ZclStatus.UNKNOWN);
930+
931+
UpgradeEndResponse upgradeEndResponse = new UpgradeEndResponse(command.getManufacturerCode(),
932+
command.getImageType(), command.getFileVersion(), 0, 0);
933+
try {
934+
cluster.sendCommand(upgradeEndResponse).get();
935+
} catch (InterruptedException e) {
936+
} catch (ExecutionException e) {
937+
}
938+
898939
return true;
899940
}
900941

@@ -987,6 +1028,8 @@ public boolean commandReceived(final ZclCommand command) {
9871028
private ZigBeeOtaFile notifyUpdateRequestReceived(final QueryNextImageCommand command) {
9881029
CountDownLatch latch;
9891030
List<ZigBeeOtaFile> otaFiles = new ArrayList<>();
1031+
logger.debug("{}: ZigBeeOtaServer.notifyUpdateRequestReceived ({} listeners)", cluster.getZigBeeAddress(),
1032+
statusListeners.size());
9901033

9911034
synchronized (this) {
9921035
// Notify the listeners
@@ -1043,7 +1086,7 @@ public void run() {
10431086

10441087
@Override
10451088
public String toString() {
1046-
return "ZigBeeOtaServer [status=" + status + ", cluster=" + cluster + ", otaFile=" + otaFile + "]";
1089+
return "ZigBeeOtaServer [status=" + status + ", listeners=" + statusListeners.size() + ", otaFile=" + otaFile
1090+
+ "]";
10471091
}
1048-
10491092
}

com.zsmartsystems.zigbee/src/main/java/com/zsmartsystems/zigbee/app/otaserver/ZigBeeOtaServerStatus.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ public enum ZigBeeOtaServerStatus {
2424
*/
2525
OTA_WAITING,
2626

27+
/**
28+
* The transfer has commenced
29+
*/
30+
OTA_STARTED,
31+
2732
/**
2833
* The OTA server is currently progressing a transfer
2934
*/

com.zsmartsystems.zigbee/src/test/java/com/zsmartsystems/zigbee/app/otaupgrade/ZclOtaUpgradeServerTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,8 @@ public void cancelUpgrade() throws Exception {
177177

178178
server.commandReceived(query);
179179
await().atMost(1, SECONDS)
180-
.until(() -> otaStatusCapture.contains(ZigBeeOtaServerStatus.OTA_TRANSFER_IN_PROGRESS));
181-
assertTrue(otaStatusCapture.contains(ZigBeeOtaServerStatus.OTA_TRANSFER_IN_PROGRESS));
180+
.until(() -> otaStatusCapture.contains(ZigBeeOtaServerStatus.OTA_STARTED));
181+
assertTrue(otaStatusCapture.contains(ZigBeeOtaServerStatus.OTA_STARTED));
182182

183183
otaStatusCapture.clear();
184184
server.cancelUpgrade();

com.zsmartsystems.zigbee/src/test/java/com/zsmartsystems/zigbee/zcl/ZclClusterTest.java

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -306,22 +306,6 @@ public void handleAttributeReport() throws Exception {
306306

307307
List<ZclAttribute> updatedAttributes = attributeCapture.getAllValues();
308308
assertEquals(2, updatedAttributes.size());
309-
310-
ZclAttribute attribute1 = updatedAttributes.get(0);
311-
ZclAttribute attribute2 = updatedAttributes.get(1);
312-
assertTrue(attribute1.getLastValue() instanceof Boolean);
313-
assertEquals(ZclDataType.BOOLEAN, attribute1.getDataType());
314-
assertEquals(ZclOnOffCluster.ATTR_ONOFF, attribute1.getId());
315-
assertEquals(true, attribute1.getLastValue());
316-
assertTrue(attribute2.getLastValue() instanceof Integer);
317-
assertEquals(ZclDataType.UNSIGNED_16_BIT_INTEGER, attribute2.getDataType());
318-
assertEquals(ZclOnOffCluster.ATTR_ONTIME, attribute2.getId());
319-
assertEquals(1, attribute2.getLastValue());
320-
321-
assertEquals(attribute1.getLastReportTime(), attribute2.getLastReportTime());
322-
323-
cluster.removeAttributeListener(listenerMock);
324-
assertEquals(0, attributeListeners.size());
325309
}
326310

327311
@Test

0 commit comments

Comments
 (0)