@willieee802/zigbee-herdsman 0.49.3 → 0.50.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (211) hide show
  1. package/.github/dependabot.yml +0 -3
  2. package/.github/workflows/ci.yml +1 -2
  3. package/.github/workflows/release-please.yml +1 -1
  4. package/.github/workflows/typedoc.yaml +3 -3
  5. package/.release-please-manifest.json +1 -1
  6. package/CHANGELOG.md +143 -0
  7. package/biome.json +1 -1
  8. package/dist/adapter/adapter.d.ts +14 -1
  9. package/dist/adapter/adapter.d.ts.map +1 -1
  10. package/dist/adapter/adapter.js +17 -0
  11. package/dist/adapter/adapter.js.map +1 -1
  12. package/dist/adapter/adapterDiscovery.d.ts.map +1 -1
  13. package/dist/adapter/adapterDiscovery.js.map +1 -1
  14. package/dist/adapter/deconz/adapter/deconzAdapter.d.ts +1 -3
  15. package/dist/adapter/deconz/adapter/deconzAdapter.d.ts.map +1 -1
  16. package/dist/adapter/deconz/adapter/deconzAdapter.js +14 -29
  17. package/dist/adapter/deconz/adapter/deconzAdapter.js.map +1 -1
  18. package/dist/adapter/deconz/driver/constants.d.ts +1 -1
  19. package/dist/adapter/deconz/driver/constants.d.ts.map +1 -1
  20. package/dist/adapter/ember/adapter/emberAdapter.d.ts +1 -1
  21. package/dist/adapter/ember/adapter/emberAdapter.d.ts.map +1 -1
  22. package/dist/adapter/ember/adapter/emberAdapter.js +19 -10
  23. package/dist/adapter/ember/adapter/emberAdapter.js.map +1 -1
  24. package/dist/adapter/ember/adapter/oneWaitress.d.ts +2 -0
  25. package/dist/adapter/ember/adapter/oneWaitress.d.ts.map +1 -1
  26. package/dist/adapter/ember/adapter/oneWaitress.js +13 -5
  27. package/dist/adapter/ember/adapter/oneWaitress.js.map +1 -1
  28. package/dist/adapter/ezsp/adapter/ezspAdapter.d.ts +1 -3
  29. package/dist/adapter/ezsp/adapter/ezspAdapter.d.ts.map +1 -1
  30. package/dist/adapter/ezsp/adapter/ezspAdapter.js +17 -30
  31. package/dist/adapter/ezsp/adapter/ezspAdapter.js.map +1 -1
  32. package/dist/adapter/ezsp/driver/index.d.ts +1 -1
  33. package/dist/adapter/ezsp/driver/index.d.ts.map +1 -1
  34. package/dist/adapter/ezsp/driver/index.js +1 -1
  35. package/dist/adapter/ezsp/driver/index.js.map +1 -1
  36. package/dist/adapter/ezsp/driver/types/index.d.ts +1 -1
  37. package/dist/adapter/ezsp/driver/types/index.d.ts.map +1 -1
  38. package/dist/adapter/ezsp/driver/types/index.js +3 -3
  39. package/dist/adapter/ezsp/driver/types/index.js.map +1 -1
  40. package/dist/adapter/serialPort.d.ts.map +1 -1
  41. package/dist/adapter/serialPort.js +7 -0
  42. package/dist/adapter/serialPort.js.map +1 -1
  43. package/dist/adapter/z-stack/adapter/adapter-backup.js +1 -1
  44. package/dist/adapter/z-stack/adapter/adapter-backup.js.map +1 -1
  45. package/dist/adapter/z-stack/adapter/adapter-nv-memory.js +1 -1
  46. package/dist/adapter/z-stack/adapter/adapter-nv-memory.js.map +1 -1
  47. package/dist/adapter/z-stack/adapter/manager.d.ts.map +1 -1
  48. package/dist/adapter/z-stack/adapter/manager.js +12 -2
  49. package/dist/adapter/z-stack/adapter/manager.js.map +1 -1
  50. package/dist/adapter/z-stack/adapter/tstype.d.ts.map +1 -1
  51. package/dist/adapter/z-stack/adapter/zStackAdapter.d.ts +1 -3
  52. package/dist/adapter/z-stack/adapter/zStackAdapter.d.ts.map +1 -1
  53. package/dist/adapter/z-stack/adapter/zStackAdapter.js +20 -34
  54. package/dist/adapter/z-stack/adapter/zStackAdapter.js.map +1 -1
  55. package/dist/adapter/z-stack/constants/index.d.ts +1 -1
  56. package/dist/adapter/z-stack/constants/index.d.ts.map +1 -1
  57. package/dist/adapter/z-stack/constants/index.js +1 -1
  58. package/dist/adapter/z-stack/constants/index.js.map +1 -1
  59. package/dist/adapter/z-stack/unpi/constants.d.ts +1 -1
  60. package/dist/adapter/z-stack/unpi/constants.d.ts.map +1 -1
  61. package/dist/adapter/z-stack/unpi/constants.js +1 -1
  62. package/dist/adapter/z-stack/unpi/constants.js.map +1 -1
  63. package/dist/adapter/zboss/adapter/zbossAdapter.d.ts +7 -8
  64. package/dist/adapter/zboss/adapter/zbossAdapter.d.ts.map +1 -1
  65. package/dist/adapter/zboss/adapter/zbossAdapter.js +12 -30
  66. package/dist/adapter/zboss/adapter/zbossAdapter.js.map +1 -1
  67. package/dist/adapter/zboss/driver.d.ts.map +1 -1
  68. package/dist/adapter/zboss/driver.js +8 -1
  69. package/dist/adapter/zboss/driver.js.map +1 -1
  70. package/dist/adapter/zboss/uart.d.ts.map +1 -1
  71. package/dist/adapter/zboss/uart.js +14 -2
  72. package/dist/adapter/zboss/uart.js.map +1 -1
  73. package/dist/adapter/zigate/adapter/zigateAdapter.d.ts +1 -3
  74. package/dist/adapter/zigate/adapter/zigateAdapter.d.ts.map +1 -1
  75. package/dist/adapter/zigate/adapter/zigateAdapter.js +8 -29
  76. package/dist/adapter/zigate/adapter/zigateAdapter.js.map +1 -1
  77. package/dist/adapter/zoh/adapter/zohAdapter.d.ts +1 -3
  78. package/dist/adapter/zoh/adapter/zohAdapter.d.ts.map +1 -1
  79. package/dist/adapter/zoh/adapter/zohAdapter.js +18 -33
  80. package/dist/adapter/zoh/adapter/zohAdapter.js.map +1 -1
  81. package/dist/controller/controller.d.ts.map +1 -1
  82. package/dist/controller/controller.js +10 -2
  83. package/dist/controller/controller.js.map +1 -1
  84. package/dist/controller/greenPower.d.ts.map +1 -1
  85. package/dist/controller/greenPower.js +15 -9
  86. package/dist/controller/greenPower.js.map +1 -1
  87. package/dist/controller/helpers/ota.d.ts +4 -4
  88. package/dist/controller/helpers/ota.d.ts.map +1 -1
  89. package/dist/controller/helpers/ota.js +28 -9
  90. package/dist/controller/helpers/ota.js.map +1 -1
  91. package/dist/controller/helpers/zclFrameConverter.d.ts.map +1 -1
  92. package/dist/controller/helpers/zclFrameConverter.js +17 -16
  93. package/dist/controller/helpers/zclFrameConverter.js.map +1 -1
  94. package/dist/controller/model/device.d.ts +14 -4
  95. package/dist/controller/model/device.d.ts.map +1 -1
  96. package/dist/controller/model/device.js +167 -85
  97. package/dist/controller/model/device.js.map +1 -1
  98. package/dist/controller/model/endpoint.d.ts +7 -3
  99. package/dist/controller/model/endpoint.d.ts.map +1 -1
  100. package/dist/controller/model/endpoint.js +34 -21
  101. package/dist/controller/model/endpoint.js.map +1 -1
  102. package/dist/controller/model/group.d.ts +0 -1
  103. package/dist/controller/model/group.d.ts.map +1 -1
  104. package/dist/controller/model/group.js +14 -19
  105. package/dist/controller/model/group.js.map +1 -1
  106. package/dist/controller/touchlink.js +3 -3
  107. package/dist/controller/touchlink.js.map +1 -1
  108. package/dist/utils/timeService.js +2 -2
  109. package/dist/utils/timeService.js.map +1 -1
  110. package/dist/zspec/zcl/buffaloZcl.d.ts +3 -3
  111. package/dist/zspec/zcl/buffaloZcl.d.ts.map +1 -1
  112. package/dist/zspec/zcl/buffaloZcl.js +198 -96
  113. package/dist/zspec/zcl/buffaloZcl.js.map +1 -1
  114. package/dist/zspec/zcl/definition/cluster.d.ts +2 -2
  115. package/dist/zspec/zcl/definition/cluster.d.ts.map +1 -1
  116. package/dist/zspec/zcl/definition/cluster.js +2699 -2808
  117. package/dist/zspec/zcl/definition/cluster.js.map +1 -1
  118. package/dist/zspec/zcl/definition/clusters-types.d.ts +63 -1109
  119. package/dist/zspec/zcl/definition/clusters-types.d.ts.map +1 -1
  120. package/dist/zspec/zcl/definition/enums.d.ts +0 -1
  121. package/dist/zspec/zcl/definition/enums.d.ts.map +1 -1
  122. package/dist/zspec/zcl/definition/enums.js +0 -1
  123. package/dist/zspec/zcl/definition/enums.js.map +1 -1
  124. package/dist/zspec/zcl/definition/foundation.d.ts +306 -7
  125. package/dist/zspec/zcl/definition/foundation.d.ts.map +1 -1
  126. package/dist/zspec/zcl/definition/foundation.js +552 -207
  127. package/dist/zspec/zcl/definition/foundation.js.map +1 -1
  128. package/dist/zspec/zcl/definition/status.d.ts +21 -10
  129. package/dist/zspec/zcl/definition/status.d.ts.map +1 -1
  130. package/dist/zspec/zcl/definition/status.js +11 -0
  131. package/dist/zspec/zcl/definition/status.js.map +1 -1
  132. package/dist/zspec/zcl/definition/tstype.d.ts +57 -48
  133. package/dist/zspec/zcl/definition/tstype.d.ts.map +1 -1
  134. package/dist/zspec/zcl/utils.d.ts +7 -4
  135. package/dist/zspec/zcl/utils.d.ts.map +1 -1
  136. package/dist/zspec/zcl/utils.js +133 -240
  137. package/dist/zspec/zcl/utils.js.map +1 -1
  138. package/dist/zspec/zcl/zclFrame.d.ts +4 -4
  139. package/dist/zspec/zcl/zclFrame.d.ts.map +1 -1
  140. package/dist/zspec/zcl/zclFrame.js +19 -103
  141. package/dist/zspec/zcl/zclFrame.js.map +1 -1
  142. package/dist/zspec/zcl/zclStatusError.d.ts +1 -1
  143. package/dist/zspec/zcl/zclStatusError.d.ts.map +1 -1
  144. package/dist/zspec/zcl/zclStatusError.js +2 -2
  145. package/dist/zspec/zcl/zclStatusError.js.map +1 -1
  146. package/package.json +1 -1
  147. package/scripts/clusters-typegen.ts +44 -139
  148. package/src/adapter/adapter.ts +38 -3
  149. package/src/adapter/adapterDiscovery.ts +2 -1
  150. package/src/adapter/deconz/adapter/deconzAdapter.ts +24 -51
  151. package/src/adapter/deconz/driver/constants.ts +1 -1
  152. package/src/adapter/ember/adapter/emberAdapter.ts +23 -10
  153. package/src/adapter/ember/adapter/oneWaitress.ts +16 -6
  154. package/src/adapter/ezsp/adapter/ezspAdapter.ts +27 -48
  155. package/src/adapter/ezsp/driver/index.ts +1 -1
  156. package/src/adapter/ezsp/driver/types/index.ts +99 -99
  157. package/src/adapter/serialPort.ts +9 -0
  158. package/src/adapter/z-stack/adapter/adapter-backup.ts +1 -1
  159. package/src/adapter/z-stack/adapter/adapter-nv-memory.ts +1 -1
  160. package/src/adapter/z-stack/adapter/manager.ts +16 -2
  161. package/src/adapter/z-stack/adapter/tstype.ts +1 -0
  162. package/src/adapter/z-stack/adapter/zStackAdapter.ts +34 -81
  163. package/src/adapter/z-stack/constants/index.ts +1 -1
  164. package/src/adapter/z-stack/unpi/constants.ts +1 -1
  165. package/src/adapter/zboss/adapter/zbossAdapter.ts +23 -54
  166. package/src/adapter/zboss/driver.ts +8 -1
  167. package/src/adapter/zboss/uart.ts +14 -1
  168. package/src/adapter/zigate/adapter/zigateAdapter.ts +17 -48
  169. package/src/adapter/zoh/adapter/zohAdapter.ts +27 -50
  170. package/src/controller/controller.ts +12 -2
  171. package/src/controller/greenPower.ts +16 -9
  172. package/src/controller/helpers/ota.ts +37 -11
  173. package/src/controller/helpers/zclFrameConverter.ts +20 -17
  174. package/src/controller/model/device.ts +204 -97
  175. package/src/controller/model/endpoint.ts +36 -24
  176. package/src/controller/model/group.ts +14 -20
  177. package/src/controller/touchlink.ts +3 -3
  178. package/src/utils/timeService.ts +2 -2
  179. package/src/zspec/zcl/buffaloZcl.ts +226 -100
  180. package/src/zspec/zcl/definition/cluster.ts +2713 -2822
  181. package/src/zspec/zcl/definition/clusters-types.ts +80 -1135
  182. package/src/zspec/zcl/definition/enums.ts +0 -1
  183. package/src/zspec/zcl/definition/foundation.ts +703 -216
  184. package/src/zspec/zcl/definition/status.ts +22 -11
  185. package/src/zspec/zcl/definition/tstype.ts +59 -58
  186. package/src/zspec/zcl/utils.ts +137 -264
  187. package/src/zspec/zcl/zclFrame.ts +25 -130
  188. package/src/zspec/zcl/zclStatusError.ts +2 -2
  189. package/test/adapter/ember/emberAdapter.test.ts +191 -4
  190. package/test/adapter/ezsp/uart.test.ts +10 -10
  191. package/test/adapter/z-stack/adapter.test.ts +88 -32
  192. package/test/adapter/zoh/zohAdapter.test.ts +4 -4
  193. package/test/controller.test.ts +822 -248
  194. package/test/device-ota.test.ts +141 -16
  195. package/test/device.test.ts +731 -0
  196. package/test/requests.bench.ts +2 -0
  197. package/test/zcl.test.ts +70 -95
  198. package/test/zspec/zcl/buffalo.test.ts +251 -11
  199. package/test/zspec/zcl/foundation.test.ts +990 -0
  200. package/test/zspec/zcl/frame.test.ts +84 -69
  201. package/test/zspec/zcl/utils.test.ts +105 -81
  202. package/tsconfig.json +0 -1
  203. package/scripts/check-clusters-changes.ts +0 -328
  204. package/scripts/clusters-changes.log +0 -584
  205. package/scripts/utils.ts +0 -88
  206. package/scripts/zap-update-clusters-report.json +0 -303
  207. package/scripts/zap-update-clusters.ts +0 -1520
  208. package/scripts/zap-update-types.ts +0 -707
  209. package/scripts/zap-xml-clusters-overrides-data.ts +0 -52
  210. package/scripts/zap-xml-clusters-overrides.ts +0 -400
  211. package/scripts/zap-xml-types.ts +0 -146
@@ -20,33 +20,38 @@ const OTA_CLUSTER_ID = Zcl.Clusters.genOta.ID;
20
20
  const QUERY_NEXT_IMAGE_REQUEST_ID = Zcl.Clusters.genOta.commands.queryNextImageRequest.ID;
21
21
  const UPGRADE_END_REQUEST_ID = Zcl.Clusters.genOta.commands.upgradeEndRequest.ID;
22
22
  const IMAGE_BLOCK_REQUEST_ID = Zcl.Clusters.genOta.commands.imageBlockRequest.ID;
23
+ const IMAGE_BLOCK_RESPONSE_ID = Zcl.Clusters.genOta.commandsResponse.imageBlockResponse.ID;
23
24
  const IMAGE_PAGE_REQUEST_ID = Zcl.Clusters.genOta.commands.imagePageRequest.ID;
24
25
 
25
26
  type OtaDeviceBehavior = {
26
27
  baseSize: number;
27
- /** Mimick the device sending image page requests instead of image block requests */
28
+ /** Mimic the device sending image page requests instead of image block requests */
28
29
  usePageRequests?: boolean;
29
30
  pageSize?: number;
30
- /** Mimick the device sending non-value (0xff) as `maximumDataSize` */
31
+ /** Mimic the device sending non-value (0xff) as `maximumDataSize` */
31
32
  useNonValueDataSize?: boolean;
32
- /** Mimick the device stopping image block/page requests at specified block (i.e. stalling) */
33
+ /** Mimic the device stopping image block/page requests at specified block (i.e. stalling) */
33
34
  stopAfterBlocks?: number;
34
- /** Mimick the device sending out-of-order offset for block/page request, block 2 swapped with block 3 */
35
+ /** Mimic a received default response after block 1. Will repeat last block. */
36
+ triggerDefaultResponse?: Zcl.Status;
37
+ /** Trigger abort after block 1. */
38
+ abort?: boolean;
39
+ /** Mimic the device sending out-of-order offset for block/page request, block 2 swapped with block 3 */
35
40
  shuffleOffsets?: boolean;
36
41
  /**
37
42
  * TODO: implement this
38
- * Mimick the device sending block/page request with an offset that is lower or higher than expected flow of "previous offset+data size" at block 2:
43
+ * Mimic the device sending block/page request with an offset that is lower or higher than expected flow of "previous offset+data size" at block 2:
39
44
  * - normal flow would be something like: block1=[offset=0, dataSize=50], block2=[offset=50, dataSize=50], block3=[offset=100, dataSize=50]
40
45
  * - with this block2 has this applied to offset: block1=[offset=0, dataSize=50], block2=[offset=(dataSize-misalignedOffset), dataSize=50], block3=[offset=(dataSize*2-misalignedOffset), dataSize=50]
41
46
  */
42
47
  misalignedOffset?: number;
43
- /** Mimick failing block 2 response (mimick device sending new image block/page request for same offset) */
44
- failBlockResponse?: boolean;
45
- /** Mimick the device sending or not of `upgradeEndRequest` (at end of block/page requests, or as specified by other behaviors) */
48
+ /** Mimic failing given block response (mimic device sending new image block/page request for same offset OR failure to abort) */
49
+ failBlockResponse?: number;
50
+ /** Mimic the device sending or not of `upgradeEndRequest` (at end of block/page requests, or as specified by other behaviors) */
46
51
  sendUpgradeEnd?: boolean;
47
- /** Mimick the device sending that specific status in `upgradeEndRequest` */
52
+ /** Mimic the device sending that specific status in `upgradeEndRequest` */
48
53
  upgradeEndStatus?: Zcl.Status;
49
- /** Mimick the device sending `upgradeEndRequest` after that specific block/page request */
54
+ /** Mimic the device sending `upgradeEndRequest` after that specific block/page request */
50
55
  upgradeEndAfterBlocks?: number;
51
56
  };
52
57
 
@@ -65,6 +70,7 @@ const createEndpointStub = () => {
65
70
  };
66
71
 
67
72
  const createOtaDeviceWaitFor = (
73
+ device: Device,
68
74
  endpoint: Endpoint,
69
75
  image: OtaImage,
70
76
  current: TClusterCommandPayload<"genOta", "queryNextImageRequest">,
@@ -110,10 +116,10 @@ const createOtaDeviceWaitFor = (
110
116
  });
111
117
  };
112
118
 
113
- if (settings.failBlockResponse) {
119
+ if (settings.failBlockResponse !== undefined) {
114
120
  endpoint.commandResponse = vi.fn((_clusterKey, commandKey, _payload, _options, _transactionSequenceNumber) => {
115
121
  if (commandKey === "imageBlockResponse") {
116
- if (blocksServed === 1) {
122
+ if (blocksServed === settings.failBlockResponse) {
117
123
  repeatLastBlock = true;
118
124
  return Promise.reject(new Error("block-fail"));
119
125
  }
@@ -132,6 +138,37 @@ const createOtaDeviceWaitFor = (
132
138
  ({offset: nextOffset} = previousBlock);
133
139
  }
134
140
 
141
+ if (blocksServed === 1 && settings.triggerDefaultResponse) {
142
+ const frame = Zcl.Frame.create(
143
+ Zcl.FrameType.GLOBAL,
144
+ Zcl.Direction.CLIENT_TO_SERVER,
145
+ true,
146
+ undefined,
147
+ transactionSequenceNumber ?? blockTsn,
148
+ "defaultRsp",
149
+ "genOta",
150
+ {cmdId: IMAGE_BLOCK_RESPONSE_ID, statusCode: settings.triggerDefaultResponse},
151
+ {},
152
+ );
153
+ repeatLastBlock = true;
154
+ settings.triggerDefaultResponse = undefined;
155
+
156
+ return {
157
+ promise: Promise.resolve({
158
+ clusterID: OTA_CLUSTER_ID,
159
+ header: frame.header,
160
+ data: frame.toBuffer(),
161
+ endpoint: endpointId,
162
+ linkquality: 0,
163
+ address: networkAddress,
164
+ groupID: 0,
165
+ wasBroadcast: false,
166
+ destinationEndpoint: endpointId,
167
+ }),
168
+ cancel: () => {},
169
+ };
170
+ }
171
+
135
172
  if (settings.stopAfterBlocks !== undefined && blocksServed >= settings.stopAfterBlocks) {
136
173
  return {
137
174
  promise: Promise.reject(new Error("device stopped requesting blocks")),
@@ -186,6 +223,10 @@ const createOtaDeviceWaitFor = (
186
223
  maybeScheduleUpgradeEnd();
187
224
  }
188
225
 
226
+ if (blocksServed === 2 && settings.abort) {
227
+ device.abortOta();
228
+ }
229
+
189
230
  return {
190
231
  promise: Promise.resolve({
191
232
  clusterID: OTA_CLUSTER_ID,
@@ -533,6 +574,7 @@ const createDevice = ({
533
574
  database.write = () => {};
534
575
  Entity.injectDatabase(database);
535
576
 
577
+ const device = Device.create("Router", "0x1", 0x1001, 1, manufacturerName, "Mains", modelID, InterviewState.Successful, undefined);
536
578
  const endpoint = createEndpointStub();
537
579
  const currentPayload: TClusterCommandPayload<"genOta", "queryNextImageRequest"> = requestPayload ?? {
538
580
  fieldControl: 0,
@@ -540,12 +582,10 @@ const createDevice = ({
540
582
  imageType: image.header.imageType,
541
583
  fileVersion: image.header.fileVersion + (source?.downgrade ? 1 : -1),
542
584
  };
543
- const waitFor = createOtaDeviceWaitFor(endpoint, image, currentPayload, {baseSize: dataSettings.baseSize, ...behavior});
585
+ const waitFor = createOtaDeviceWaitFor(device, endpoint, image, currentPayload, {baseSize: dataSettings.baseSize, ...behavior});
544
586
  const adapter = {waitFor, hasZdoMessageOverhead: false} as unknown as Adapter;
545
587
  Entity.injectAdapter(adapter);
546
588
 
547
- const device = Device.create("Router", "0x1", 0x1001, 1, manufacturerName, "Mains", modelID, InterviewState.Successful, undefined);
548
-
549
589
  if (autoAnnounce) {
550
590
  const originalOnce = device.once.bind(device);
551
591
 
@@ -1166,6 +1206,61 @@ describe("Device OTA", () => {
1166
1206
  expect(device.otaInProgress).toStrictEqual(false);
1167
1207
  });
1168
1208
 
1209
+ it("aborts an in-progress update", async () => {
1210
+ const fileName = OTA_FILES[0];
1211
+ const [image] = await loadImage(fileName);
1212
+ firmwareBuffer = image.raw;
1213
+ const requestPayload: TClusterCommandPayload<"genOta", "queryNextImageRequest"> = {
1214
+ fieldControl: 0,
1215
+ manufacturerCode: image.header.manufacturerCode,
1216
+ imageType: image.header.imageType,
1217
+ fileVersion: image.header.fileVersion - 1,
1218
+ };
1219
+ const baseSize = 55;
1220
+
1221
+ const {device, endpoint, run} = createDevice({
1222
+ image,
1223
+ source: {},
1224
+ requestPayload,
1225
+ dataSettings: {requestTimeout: 1000, responseDelay: 0, baseSize},
1226
+ behavior: {baseSize, sendUpgradeEnd: true, abort: true},
1227
+ });
1228
+
1229
+ await expect(run()).rejects.toThrow(/OTA.*was aborted/);
1230
+ const calls = getResponses(endpoint, "imageBlockResponse");
1231
+ expect(getResponses(endpoint, "imageBlockResponse").length).toStrictEqual(2);
1232
+ expect(calls[1][2]).toStrictEqual({status: Zcl.Status.ABORT});
1233
+ expect(device.otaInProgress).toStrictEqual(false);
1234
+ });
1235
+
1236
+ it("fails to abort an in-progress update", async () => {
1237
+ // this is same as success for ZH, only the device may not have aborted itself
1238
+ const fileName = OTA_FILES[0];
1239
+ const [image] = await loadImage(fileName);
1240
+ firmwareBuffer = image.raw;
1241
+ const requestPayload: TClusterCommandPayload<"genOta", "queryNextImageRequest"> = {
1242
+ fieldControl: 0,
1243
+ manufacturerCode: image.header.manufacturerCode,
1244
+ imageType: image.header.imageType,
1245
+ fileVersion: image.header.fileVersion - 1,
1246
+ };
1247
+ const baseSize = 55;
1248
+
1249
+ const {device, endpoint, run} = createDevice({
1250
+ image,
1251
+ source: {},
1252
+ requestPayload,
1253
+ dataSettings: {requestTimeout: 1000, responseDelay: 0, baseSize},
1254
+ behavior: {baseSize, sendUpgradeEnd: true, abort: true, failBlockResponse: 2},
1255
+ });
1256
+
1257
+ await expect(run()).rejects.toThrow(/OTA.*was aborted/);
1258
+ const calls = getResponses(endpoint, "imageBlockResponse");
1259
+ expect(getResponses(endpoint, "imageBlockResponse").length).toStrictEqual(2);
1260
+ expect(calls[1][2]).toStrictEqual({status: Zcl.Status.ABORT});
1261
+ expect(device.otaInProgress).toStrictEqual(false);
1262
+ });
1263
+
1169
1264
  it("considers an upgrade successful even if no device announce", async () => {
1170
1265
  const fileName = OTA_FILES[0];
1171
1266
  const [image] = await loadImage(fileName);
@@ -1227,6 +1322,36 @@ describe("Device OTA", () => {
1227
1322
  expect(device.otaInProgress).toStrictEqual(false);
1228
1323
  });
1229
1324
 
1325
+ it("handles receiving default response after block response", async () => {
1326
+ const fileName = OTA_FILES[0];
1327
+ const [image] = await loadImage(fileName);
1328
+ firmwareBuffer = image.raw;
1329
+ const requestPayload: TClusterCommandPayload<"genOta", "queryNextImageRequest"> = {
1330
+ fieldControl: 0,
1331
+ manufacturerCode: image.header.manufacturerCode,
1332
+ imageType: image.header.imageType,
1333
+ fileVersion: image.header.fileVersion - 1,
1334
+ };
1335
+ const baseSize = 55;
1336
+ const expectedBlocks = Math.ceil(image.header.totalImageSize / baseSize);
1337
+
1338
+ const {device, endpoint, run} = createDevice({
1339
+ image,
1340
+ source: {},
1341
+ requestPayload,
1342
+ dataSettings: {requestTimeout: 1000, responseDelay: 0, baseSize},
1343
+ behavior: {baseSize, sendUpgradeEnd: true, triggerDefaultResponse: Zcl.Status.MALFORMED_COMMAND},
1344
+ });
1345
+
1346
+ const [from, to] = await run();
1347
+
1348
+ expect(from.fileVersion).toStrictEqual(requestPayload.fileVersion);
1349
+ expect(to?.fileVersion).toStrictEqual(image.header.fileVersion);
1350
+ expect(getResponses(endpoint, "imageBlockResponse").length).toStrictEqual(expectedBlocks + 1);
1351
+ expect(getResponses(endpoint, "upgradeEndResponse").length).toStrictEqual(1);
1352
+ expect(device.otaInProgress).toStrictEqual(false);
1353
+ });
1354
+
1230
1355
  it("handles out-of-order block offsets", async () => {
1231
1356
  const fileName = OTA_FILES[0];
1232
1357
  const [image] = await loadImage(fileName);
@@ -2138,7 +2263,7 @@ describe("Device OTA", () => {
2138
2263
  image,
2139
2264
  source: {},
2140
2265
  dataSettings,
2141
- behavior: {baseSize, sendUpgradeEnd: true, failBlockResponse: true},
2266
+ behavior: {baseSize, sendUpgradeEnd: true, failBlockResponse: 1},
2142
2267
  });
2143
2268
 
2144
2269
  const [from, to] = await run();