Commit 1f6210197c07da752622ddeecfe10a66a8eddf34
Committed by
GitHub
Merge pull request #4959 from YevhenBondarenko/feature/ota-tag
[3.3.0] OtaPackage Tag
Showing
21 changed files
with
185 additions
and
108 deletions
@@ -67,6 +67,7 @@ CREATE TABLE IF NOT EXISTS ota_package ( | @@ -67,6 +67,7 @@ CREATE TABLE IF NOT EXISTS ota_package ( | ||
67 | type varchar(32) NOT NULL, | 67 | type varchar(32) NOT NULL, |
68 | title varchar(255) NOT NULL, | 68 | title varchar(255) NOT NULL, |
69 | version varchar(255) NOT NULL, | 69 | version varchar(255) NOT NULL, |
70 | + tag varchar(255), | ||
70 | url varchar(255), | 71 | url varchar(255), |
71 | file_name varchar(255), | 72 | file_name varchar(255), |
72 | content_type varchar(255), | 73 | content_type varchar(255), |
@@ -146,6 +146,7 @@ public class OtaPackageController extends BaseController { | @@ -146,6 +146,7 @@ public class OtaPackageController extends BaseController { | ||
146 | otaPackage.setType(info.getType()); | 146 | otaPackage.setType(info.getType()); |
147 | otaPackage.setTitle(info.getTitle()); | 147 | otaPackage.setTitle(info.getTitle()); |
148 | otaPackage.setVersion(info.getVersion()); | 148 | otaPackage.setVersion(info.getVersion()); |
149 | + otaPackage.setTag(info.getTag()); | ||
149 | otaPackage.setAdditionalInfo(info.getAdditionalInfo()); | 150 | otaPackage.setAdditionalInfo(info.getAdditionalInfo()); |
150 | 151 | ||
151 | ChecksumAlgorithm checksumAlgorithm = ChecksumAlgorithm.valueOf(checksumAlgorithmStr.toUpperCase()); | 152 | ChecksumAlgorithm checksumAlgorithm = ChecksumAlgorithm.valueOf(checksumAlgorithmStr.toUpperCase()); |
@@ -64,6 +64,7 @@ import static org.thingsboard.server.common.data.ota.OtaPackageKey.CHECKSUM; | @@ -64,6 +64,7 @@ import static org.thingsboard.server.common.data.ota.OtaPackageKey.CHECKSUM; | ||
64 | import static org.thingsboard.server.common.data.ota.OtaPackageKey.CHECKSUM_ALGORITHM; | 64 | import static org.thingsboard.server.common.data.ota.OtaPackageKey.CHECKSUM_ALGORITHM; |
65 | import static org.thingsboard.server.common.data.ota.OtaPackageKey.SIZE; | 65 | import static org.thingsboard.server.common.data.ota.OtaPackageKey.SIZE; |
66 | import static org.thingsboard.server.common.data.ota.OtaPackageKey.STATE; | 66 | import static org.thingsboard.server.common.data.ota.OtaPackageKey.STATE; |
67 | +import static org.thingsboard.server.common.data.ota.OtaPackageKey.TAG; | ||
67 | import static org.thingsboard.server.common.data.ota.OtaPackageKey.TITLE; | 68 | import static org.thingsboard.server.common.data.ota.OtaPackageKey.TITLE; |
68 | import static org.thingsboard.server.common.data.ota.OtaPackageKey.TS; | 69 | import static org.thingsboard.server.common.data.ota.OtaPackageKey.TS; |
69 | import static org.thingsboard.server.common.data.ota.OtaPackageKey.URL; | 70 | import static org.thingsboard.server.common.data.ota.OtaPackageKey.URL; |
@@ -246,6 +247,11 @@ public class DefaultOtaPackageStateService implements OtaPackageStateService { | @@ -246,6 +247,11 @@ public class DefaultOtaPackageStateService implements OtaPackageStateService { | ||
246 | List<TsKvEntry> telemetry = new ArrayList<>(); | 247 | List<TsKvEntry> telemetry = new ArrayList<>(); |
247 | telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(getTargetTelemetryKey(firmware.getType(), TITLE), firmware.getTitle()))); | 248 | telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(getTargetTelemetryKey(firmware.getType(), TITLE), firmware.getTitle()))); |
248 | telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(getTargetTelemetryKey(firmware.getType(), VERSION), firmware.getVersion()))); | 249 | telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(getTargetTelemetryKey(firmware.getType(), VERSION), firmware.getVersion()))); |
250 | + | ||
251 | + if (StringUtils.isNotEmpty(firmware.getTag())) { | ||
252 | + telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(getTargetTelemetryKey(firmware.getType(), TAG), firmware.getTag()))); | ||
253 | + } | ||
254 | + | ||
249 | telemetry.add(new BasicTsKvEntry(ts, new LongDataEntry(getTargetTelemetryKey(firmware.getType(), TS), ts))); | 255 | telemetry.add(new BasicTsKvEntry(ts, new LongDataEntry(getTargetTelemetryKey(firmware.getType(), TS), ts))); |
250 | telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(getTelemetryKey(firmware.getType(), STATE), OtaPackageUpdateStatus.QUEUED.name()))); | 256 | telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(getTelemetryKey(firmware.getType(), STATE), OtaPackageUpdateStatus.QUEUED.name()))); |
251 | 257 | ||
@@ -289,6 +295,9 @@ public class DefaultOtaPackageStateService implements OtaPackageStateService { | @@ -289,6 +295,9 @@ public class DefaultOtaPackageStateService implements OtaPackageStateService { | ||
289 | List<AttributeKvEntry> attributes = new ArrayList<>(); | 295 | List<AttributeKvEntry> attributes = new ArrayList<>(); |
290 | attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(getAttributeKey(otaPackageType, TITLE), otaPackage.getTitle()))); | 296 | attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(getAttributeKey(otaPackageType, TITLE), otaPackage.getTitle()))); |
291 | attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(getAttributeKey(otaPackageType, VERSION), otaPackage.getVersion()))); | 297 | attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(getAttributeKey(otaPackageType, VERSION), otaPackage.getVersion()))); |
298 | + if (StringUtils.isNotEmpty(otaPackage.getTag())) { | ||
299 | + attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(getAttributeKey(otaPackageType, TAG), otaPackage.getTag()))); | ||
300 | + } | ||
292 | if (otaPackage.hasUrl()) { | 301 | if (otaPackage.hasUrl()) { |
293 | attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(getAttributeKey(otaPackageType, URL), otaPackage.getUrl()))); | 302 | attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(getAttributeKey(otaPackageType, URL), otaPackage.getUrl()))); |
294 | List<String> attrToRemove = new ArrayList<>(); | 303 | List<String> attrToRemove = new ArrayList<>(); |
@@ -37,6 +37,7 @@ public class OtaPackageInfo extends SearchTextBasedWithAdditionalInfo<OtaPackage | @@ -37,6 +37,7 @@ public class OtaPackageInfo extends SearchTextBasedWithAdditionalInfo<OtaPackage | ||
37 | private OtaPackageType type; | 37 | private OtaPackageType type; |
38 | private String title; | 38 | private String title; |
39 | private String version; | 39 | private String version; |
40 | + private String tag; | ||
40 | private String url; | 41 | private String url; |
41 | private boolean hasData; | 42 | private boolean hasData; |
42 | private String fileName; | 43 | private String fileName; |
@@ -61,6 +62,7 @@ public class OtaPackageInfo extends SearchTextBasedWithAdditionalInfo<OtaPackage | @@ -61,6 +62,7 @@ public class OtaPackageInfo extends SearchTextBasedWithAdditionalInfo<OtaPackage | ||
61 | this.type = otaPackageInfo.getType(); | 62 | this.type = otaPackageInfo.getType(); |
62 | this.title = otaPackageInfo.getTitle(); | 63 | this.title = otaPackageInfo.getTitle(); |
63 | this.version = otaPackageInfo.getVersion(); | 64 | this.version = otaPackageInfo.getVersion(); |
65 | + this.tag = otaPackageInfo.getTag(); | ||
64 | this.url = otaPackageInfo.getUrl(); | 66 | this.url = otaPackageInfo.getUrl(); |
65 | this.hasData = otaPackageInfo.isHasData(); | 67 | this.hasData = otaPackageInfo.isHasData(); |
66 | this.fileName = otaPackageInfo.getFileName(); | 68 | this.fileName = otaPackageInfo.getFileName(); |
@@ -19,7 +19,7 @@ import lombok.Getter; | @@ -19,7 +19,7 @@ import lombok.Getter; | ||
19 | 19 | ||
20 | public enum OtaPackageKey { | 20 | public enum OtaPackageKey { |
21 | 21 | ||
22 | - TITLE("title"), VERSION("version"), TS("ts"), STATE("state"), SIZE("size"), CHECKSUM("checksum"), CHECKSUM_ALGORITHM("checksum_algorithm"), URL("url"); | 22 | + TITLE("title"), VERSION("version"), TS("ts"), STATE("state"), SIZE("size"), CHECKSUM("checksum"), CHECKSUM_ALGORITHM("checksum_algorithm"), URL("url"), TAG("tag"); |
23 | 23 | ||
24 | @Getter | 24 | @Getter |
25 | private final String value; | 25 | private final String value; |
@@ -120,9 +120,11 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { | @@ -120,9 +120,11 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { | ||
120 | if (msg.getSharedUpdatedCount() > 0 && lwM2MClient != null) { | 120 | if (msg.getSharedUpdatedCount() > 0 && lwM2MClient != null) { |
121 | String newFirmwareTitle = null; | 121 | String newFirmwareTitle = null; |
122 | String newFirmwareVersion = null; | 122 | String newFirmwareVersion = null; |
123 | + String newFirmwareTag = null; | ||
123 | String newFirmwareUrl = null; | 124 | String newFirmwareUrl = null; |
124 | String newSoftwareTitle = null; | 125 | String newSoftwareTitle = null; |
125 | String newSoftwareVersion = null; | 126 | String newSoftwareVersion = null; |
127 | + String newSoftwareTag = null; | ||
126 | String newSoftwareUrl = null; | 128 | String newSoftwareUrl = null; |
127 | List<TransportProtos.TsKvProto> otherAttributes = new ArrayList<>(); | 129 | List<TransportProtos.TsKvProto> otherAttributes = new ArrayList<>(); |
128 | for (TransportProtos.TsKvProto tsKvProto : msg.getSharedUpdatedList()) { | 130 | for (TransportProtos.TsKvProto tsKvProto : msg.getSharedUpdatedList()) { |
@@ -131,12 +133,16 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { | @@ -131,12 +133,16 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { | ||
131 | newFirmwareTitle = getStrValue(tsKvProto); | 133 | newFirmwareTitle = getStrValue(tsKvProto); |
132 | } else if (DefaultLwM2MOtaUpdateService.FIRMWARE_VERSION.equals(attrName)) { | 134 | } else if (DefaultLwM2MOtaUpdateService.FIRMWARE_VERSION.equals(attrName)) { |
133 | newFirmwareVersion = getStrValue(tsKvProto); | 135 | newFirmwareVersion = getStrValue(tsKvProto); |
136 | + } else if (DefaultLwM2MOtaUpdateService.FIRMWARE_TAG.equals(attrName)) { | ||
137 | + newFirmwareTag = getStrValue(tsKvProto); | ||
134 | } else if (DefaultLwM2MOtaUpdateService.FIRMWARE_URL.equals(attrName)) { | 138 | } else if (DefaultLwM2MOtaUpdateService.FIRMWARE_URL.equals(attrName)) { |
135 | newFirmwareUrl = getStrValue(tsKvProto); | 139 | newFirmwareUrl = getStrValue(tsKvProto); |
136 | } else if (DefaultLwM2MOtaUpdateService.SOFTWARE_TITLE.equals(attrName)) { | 140 | } else if (DefaultLwM2MOtaUpdateService.SOFTWARE_TITLE.equals(attrName)) { |
137 | newSoftwareTitle = getStrValue(tsKvProto); | 141 | newSoftwareTitle = getStrValue(tsKvProto); |
138 | } else if (DefaultLwM2MOtaUpdateService.SOFTWARE_VERSION.equals(attrName)) { | 142 | } else if (DefaultLwM2MOtaUpdateService.SOFTWARE_VERSION.equals(attrName)) { |
139 | newSoftwareVersion = getStrValue(tsKvProto); | 143 | newSoftwareVersion = getStrValue(tsKvProto); |
144 | + } else if (DefaultLwM2MOtaUpdateService.SOFTWARE_TAG.equals(attrName)) { | ||
145 | + newSoftwareTag = getStrValue(tsKvProto); | ||
140 | } else if (DefaultLwM2MOtaUpdateService.SOFTWARE_URL.equals(attrName)) { | 146 | } else if (DefaultLwM2MOtaUpdateService.SOFTWARE_URL.equals(attrName)) { |
141 | newSoftwareUrl = getStrValue(tsKvProto); | 147 | newSoftwareUrl = getStrValue(tsKvProto); |
142 | }else { | 148 | }else { |
@@ -144,10 +150,10 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { | @@ -144,10 +150,10 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { | ||
144 | } | 150 | } |
145 | } | 151 | } |
146 | if (newFirmwareTitle != null || newFirmwareVersion != null) { | 152 | if (newFirmwareTitle != null || newFirmwareVersion != null) { |
147 | - otaUpdateService.onTargetFirmwareUpdate(lwM2MClient, newFirmwareTitle, newFirmwareVersion, Optional.ofNullable(newFirmwareUrl)); | 153 | + otaUpdateService.onTargetFirmwareUpdate(lwM2MClient, newFirmwareTitle, newFirmwareVersion, Optional.ofNullable(newFirmwareUrl), Optional.ofNullable(newFirmwareTag)); |
148 | } | 154 | } |
149 | if (newSoftwareTitle != null || newSoftwareVersion != null) { | 155 | if (newSoftwareTitle != null || newSoftwareVersion != null) { |
150 | - otaUpdateService.onTargetSoftwareUpdate(lwM2MClient, newSoftwareTitle, newSoftwareVersion, Optional.ofNullable(newSoftwareUrl)); | 156 | + otaUpdateService.onTargetSoftwareUpdate(lwM2MClient, newSoftwareTitle, newSoftwareVersion, Optional.ofNullable(newSoftwareUrl), Optional.ofNullable(newSoftwareTag)); |
151 | } | 157 | } |
152 | if (!otherAttributes.isEmpty()) { | 158 | if (!otherAttributes.isEmpty()) { |
153 | onAttributesUpdate(lwM2MClient, otherAttributes); | 159 | onAttributesUpdate(lwM2MClient, otherAttributes); |
@@ -85,9 +85,11 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl | @@ -85,9 +85,11 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl | ||
85 | 85 | ||
86 | public static final String FIRMWARE_VERSION = getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.VERSION); | 86 | public static final String FIRMWARE_VERSION = getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.VERSION); |
87 | public static final String FIRMWARE_TITLE = getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.TITLE); | 87 | public static final String FIRMWARE_TITLE = getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.TITLE); |
88 | + public static final String FIRMWARE_TAG = getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.TAG); | ||
88 | public static final String FIRMWARE_URL = getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.URL); | 89 | public static final String FIRMWARE_URL = getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.URL); |
89 | public static final String SOFTWARE_VERSION = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.VERSION); | 90 | public static final String SOFTWARE_VERSION = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.VERSION); |
90 | public static final String SOFTWARE_TITLE = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.TITLE); | 91 | public static final String SOFTWARE_TITLE = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.TITLE); |
92 | + public static final String SOFTWARE_TAG = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.TAG); | ||
91 | public static final String SOFTWARE_URL = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.URL); | 93 | public static final String SOFTWARE_URL = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.URL); |
92 | 94 | ||
93 | public static final String FIRMWARE_UPDATE_COAP_RESOURCE = "tbfw"; | 95 | public static final String FIRMWARE_UPDATE_COAP_RESOURCE = "tbfw"; |
@@ -165,6 +167,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl | @@ -165,6 +167,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl | ||
165 | if (fwInfo.isSupported()) { | 167 | if (fwInfo.isSupported()) { |
166 | attributesToFetch.add(FIRMWARE_TITLE); | 168 | attributesToFetch.add(FIRMWARE_TITLE); |
167 | attributesToFetch.add(FIRMWARE_VERSION); | 169 | attributesToFetch.add(FIRMWARE_VERSION); |
170 | + attributesToFetch.add(FIRMWARE_TAG); | ||
168 | attributesToFetch.add(FIRMWARE_URL); | 171 | attributesToFetch.add(FIRMWARE_URL); |
169 | } | 172 | } |
170 | 173 | ||
@@ -172,6 +175,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl | @@ -172,6 +175,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl | ||
172 | if (swInfo.isSupported()) { | 175 | if (swInfo.isSupported()) { |
173 | attributesToFetch.add(SOFTWARE_TITLE); | 176 | attributesToFetch.add(SOFTWARE_TITLE); |
174 | attributesToFetch.add(SOFTWARE_VERSION); | 177 | attributesToFetch.add(SOFTWARE_VERSION); |
178 | + attributesToFetch.add(SOFTWARE_TAG); | ||
175 | attributesToFetch.add(SOFTWARE_URL); | 179 | attributesToFetch.add(SOFTWARE_URL); |
176 | } | 180 | } |
177 | 181 | ||
@@ -186,17 +190,19 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl | @@ -186,17 +190,19 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl | ||
186 | if (fwInfo.isSupported()) { | 190 | if (fwInfo.isSupported()) { |
187 | Optional<String> newFwTitle = getAttributeValue(attrs, FIRMWARE_TITLE); | 191 | Optional<String> newFwTitle = getAttributeValue(attrs, FIRMWARE_TITLE); |
188 | Optional<String> newFwVersion = getAttributeValue(attrs, FIRMWARE_VERSION); | 192 | Optional<String> newFwVersion = getAttributeValue(attrs, FIRMWARE_VERSION); |
193 | + Optional<String> newFwTag = getAttributeValue(attrs, FIRMWARE_TAG); | ||
189 | Optional<String> newFwUrl = getAttributeValue(attrs, FIRMWARE_URL); | 194 | Optional<String> newFwUrl = getAttributeValue(attrs, FIRMWARE_URL); |
190 | if (newFwTitle.isPresent() && newFwVersion.isPresent()) { | 195 | if (newFwTitle.isPresent() && newFwVersion.isPresent()) { |
191 | - onTargetFirmwareUpdate(client, newFwTitle.get(), newFwVersion.get(), newFwUrl); | 196 | + onTargetFirmwareUpdate(client, newFwTitle.get(), newFwVersion.get(), newFwUrl, newFwTag); |
192 | } | 197 | } |
193 | } | 198 | } |
194 | if (swInfo.isSupported()) { | 199 | if (swInfo.isSupported()) { |
195 | Optional<String> newSwTitle = getAttributeValue(attrs, SOFTWARE_TITLE); | 200 | Optional<String> newSwTitle = getAttributeValue(attrs, SOFTWARE_TITLE); |
196 | Optional<String> newSwVersion = getAttributeValue(attrs, SOFTWARE_VERSION); | 201 | Optional<String> newSwVersion = getAttributeValue(attrs, SOFTWARE_VERSION); |
202 | + Optional<String> newSwTag = getAttributeValue(attrs, SOFTWARE_TAG); | ||
197 | Optional<String> newSwUrl = getAttributeValue(attrs, SOFTWARE_URL); | 203 | Optional<String> newSwUrl = getAttributeValue(attrs, SOFTWARE_URL); |
198 | if (newSwTitle.isPresent() && newSwVersion.isPresent()) { | 204 | if (newSwTitle.isPresent() && newSwVersion.isPresent()) { |
199 | - onTargetSoftwareUpdate(client, newSwTitle.get(), newSwVersion.get(), newSwUrl); | 205 | + onTargetSoftwareUpdate(client, newSwTitle.get(), newSwVersion.get(), newSwUrl, newSwTag); |
200 | } | 206 | } |
201 | } | 207 | } |
202 | }, throwable -> { | 208 | }, throwable -> { |
@@ -216,9 +222,9 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl | @@ -216,9 +222,9 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl | ||
216 | } | 222 | } |
217 | 223 | ||
218 | @Override | 224 | @Override |
219 | - public void onTargetFirmwareUpdate(LwM2mClient client, String newFirmwareTitle, String newFirmwareVersion, Optional<String> newFirmwareUrl) { | 225 | + public void onTargetFirmwareUpdate(LwM2mClient client, String newFirmwareTitle, String newFirmwareVersion, Optional<String> newFirmwareUrl, Optional<String> newFirmwareTag) { |
220 | LwM2MClientFwOtaInfo fwInfo = getOrInitFwInfo(client); | 226 | LwM2MClientFwOtaInfo fwInfo = getOrInitFwInfo(client); |
221 | - fwInfo.updateTarget(newFirmwareTitle, newFirmwareVersion, newFirmwareUrl); | 227 | + fwInfo.updateTarget(newFirmwareTitle, newFirmwareVersion, newFirmwareUrl, newFirmwareTag); |
222 | update(fwInfo); | 228 | update(fwInfo); |
223 | startFirmwareUpdateIfNeeded(client, fwInfo); | 229 | startFirmwareUpdateIfNeeded(client, fwInfo); |
224 | } | 230 | } |
@@ -354,9 +360,9 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl | @@ -354,9 +360,9 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl | ||
354 | } | 360 | } |
355 | 361 | ||
356 | @Override | 362 | @Override |
357 | - public void onTargetSoftwareUpdate(LwM2mClient client, String newSoftwareTitle, String newSoftwareVersion, Optional<String> newFirmwareUrl) { | 363 | + public void onTargetSoftwareUpdate(LwM2mClient client, String newSoftwareTitle, String newSoftwareVersion, Optional<String> newSoftwareUrl, Optional<String> newSoftwareTag) { |
358 | LwM2MClientSwOtaInfo fwInfo = getOrInitSwInfo(client); | 364 | LwM2MClientSwOtaInfo fwInfo = getOrInitSwInfo(client); |
359 | - fwInfo.updateTarget(newSoftwareTitle, newSoftwareVersion, newFirmwareUrl); | 365 | + fwInfo.updateTarget(newSoftwareTitle, newSoftwareVersion, newSoftwareUrl, newSoftwareTag); |
360 | update(fwInfo); | 366 | update(fwInfo); |
361 | startSoftwareUpdateIfNeeded(client, fwInfo); | 367 | startSoftwareUpdateIfNeeded(client, fwInfo); |
362 | } | 368 | } |
@@ -368,7 +374,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl | @@ -368,7 +374,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl | ||
368 | sendStateUpdateToTelemetry(client, fwInfo, OtaPackageUpdateStatus.FAILED, "Client does not support firmware update or profile misconfiguration!"); | 374 | sendStateUpdateToTelemetry(client, fwInfo, OtaPackageUpdateStatus.FAILED, "Client does not support firmware update or profile misconfiguration!"); |
369 | } else if (fwInfo.isUpdateRequired()) { | 375 | } else if (fwInfo.isUpdateRequired()) { |
370 | if (StringUtils.isNotEmpty(fwInfo.getTargetUrl())) { | 376 | if (StringUtils.isNotEmpty(fwInfo.getTargetUrl())) { |
371 | - log.debug("[{}] Starting update to [{}{}] using URL: {}", client.getEndpoint(), fwInfo.getTargetName(), fwInfo.getTargetVersion(), fwInfo.getTargetUrl()); | 377 | + log.debug("[{}] Starting update to [{}{}][] using URL: {}", client.getEndpoint(), fwInfo.getTargetName(), fwInfo.getTargetVersion(), fwInfo.getTargetUrl()); |
372 | startUpdateUsingUrl(client, FW_URL_ID, fwInfo.getTargetUrl()); | 378 | startUpdateUsingUrl(client, FW_URL_ID, fwInfo.getTargetUrl()); |
373 | } else { | 379 | } else { |
374 | log.debug("[{}] Starting update to [{}{}] using binary", client.getEndpoint(), fwInfo.getTargetName(), fwInfo.getTargetVersion()); | 380 | log.debug("[{}] Starting update to [{}{}] using binary", client.getEndpoint(), fwInfo.getTargetName(), fwInfo.getTargetVersion()); |
@@ -32,6 +32,7 @@ public abstract class LwM2MClientOtaInfo<Strategy, State, Result> { | @@ -32,6 +32,7 @@ public abstract class LwM2MClientOtaInfo<Strategy, State, Result> { | ||
32 | 32 | ||
33 | protected String targetName; | 33 | protected String targetName; |
34 | protected String targetVersion; | 34 | protected String targetVersion; |
35 | + protected String targetTag; | ||
35 | protected String targetUrl; | 36 | protected String targetUrl; |
36 | 37 | ||
37 | //TODO: use value from device if applicable; | 38 | //TODO: use value from device if applicable; |
@@ -52,10 +53,11 @@ public abstract class LwM2MClientOtaInfo<Strategy, State, Result> { | @@ -52,10 +53,11 @@ public abstract class LwM2MClientOtaInfo<Strategy, State, Result> { | ||
52 | this.strategy = strategy; | 53 | this.strategy = strategy; |
53 | } | 54 | } |
54 | 55 | ||
55 | - public void updateTarget(String targetName, String targetVersion, Optional<String> newTargetUrl) { | 56 | + public void updateTarget(String targetName, String targetVersion, Optional<String> newTargetUrl, Optional<String> newTargetTag) { |
56 | this.targetName = targetName; | 57 | this.targetName = targetName; |
57 | this.targetVersion = targetVersion; | 58 | this.targetVersion = targetVersion; |
58 | this.targetUrl = newTargetUrl.orElse(null); | 59 | this.targetUrl = newTargetUrl.orElse(null); |
60 | + this.targetTag = newTargetTag.orElse(null); | ||
59 | } | 61 | } |
60 | 62 | ||
61 | @JsonIgnore | 63 | @JsonIgnore |
@@ -64,13 +66,18 @@ public abstract class LwM2MClientOtaInfo<Strategy, State, Result> { | @@ -64,13 +66,18 @@ public abstract class LwM2MClientOtaInfo<Strategy, State, Result> { | ||
64 | return false; | 66 | return false; |
65 | } else { | 67 | } else { |
66 | String targetPackageId = getPackageId(targetName, targetVersion); | 68 | String targetPackageId = getPackageId(targetName, targetVersion); |
67 | - String currentPackageIdUsingObject5 = getPackageId(currentName, currentVersion); | 69 | + String currentPackageId = getPackageId(currentName, currentVersion); |
68 | if (StringUtils.isNotEmpty(failedPackageId) && failedPackageId.equals(targetPackageId)) { | 70 | if (StringUtils.isNotEmpty(failedPackageId) && failedPackageId.equals(targetPackageId)) { |
69 | return false; | 71 | return false; |
70 | } else { | 72 | } else { |
71 | - if (targetPackageId.equals(currentPackageIdUsingObject5)) { | 73 | + if (targetPackageId.equals(currentPackageId)) { |
74 | + return false; | ||
75 | + } else if (StringUtils.isNotEmpty(targetTag) && targetTag.equals(currentPackageId)) { | ||
72 | return false; | 76 | return false; |
73 | } else if (StringUtils.isNotEmpty(currentVersion3)) { | 77 | } else if (StringUtils.isNotEmpty(currentVersion3)) { |
78 | + if (StringUtils.isNotEmpty(targetTag) && currentVersion3.contains(targetTag)) { | ||
79 | + return false; | ||
80 | + } | ||
74 | return !currentVersion3.contains(targetPackageId); | 81 | return !currentVersion3.contains(targetPackageId); |
75 | } else { | 82 | } else { |
76 | return true; | 83 | return true; |
@@ -26,9 +26,9 @@ public interface LwM2MOtaUpdateService { | @@ -26,9 +26,9 @@ public interface LwM2MOtaUpdateService { | ||
26 | 26 | ||
27 | void forceFirmwareUpdate(LwM2mClient client); | 27 | void forceFirmwareUpdate(LwM2mClient client); |
28 | 28 | ||
29 | - void onTargetFirmwareUpdate(LwM2mClient client, String newFwTitle, String newFwVersion, Optional<String> newFwUrl); | 29 | + void onTargetFirmwareUpdate(LwM2mClient client, String newFwTitle, String newFwVersion, Optional<String> newFwUrl, Optional<String> newFwTag); |
30 | 30 | ||
31 | - void onTargetSoftwareUpdate(LwM2mClient client, String newSwTitle, String newSwVersion, Optional<String> newSwUrl); | 31 | + void onTargetSoftwareUpdate(LwM2mClient client, String newSwTitle, String newSwVersion, Optional<String> newSwUrl, Optional<String> newSwTag); |
32 | 32 | ||
33 | void onCurrentFirmwareNameUpdate(LwM2mClient client, String name); | 33 | void onCurrentFirmwareNameUpdate(LwM2mClient client, String name); |
34 | 34 |
@@ -499,6 +499,7 @@ public class ModelConstants { | @@ -499,6 +499,7 @@ public class ModelConstants { | ||
499 | public static final String OTA_PACKAGE_TYPE_COLUMN = "type"; | 499 | public static final String OTA_PACKAGE_TYPE_COLUMN = "type"; |
500 | public static final String OTA_PACKAGE_TILE_COLUMN = TITLE_PROPERTY; | 500 | public static final String OTA_PACKAGE_TILE_COLUMN = TITLE_PROPERTY; |
501 | public static final String OTA_PACKAGE_VERSION_COLUMN = "version"; | 501 | public static final String OTA_PACKAGE_VERSION_COLUMN = "version"; |
502 | + public static final String OTA_PACKAGE_TAG_COLUMN = "tag"; | ||
502 | public static final String OTA_PACKAGE_URL_COLUMN = "url"; | 503 | public static final String OTA_PACKAGE_URL_COLUMN = "url"; |
503 | public static final String OTA_PACKAGE_FILE_NAME_COLUMN = "file_name"; | 504 | public static final String OTA_PACKAGE_FILE_NAME_COLUMN = "file_name"; |
504 | public static final String OTA_PACKAGE_CONTENT_TYPE_COLUMN = "content_type"; | 505 | public static final String OTA_PACKAGE_CONTENT_TYPE_COLUMN = "content_type"; |
@@ -48,6 +48,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_DATA_S | @@ -48,6 +48,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_DATA_S | ||
48 | import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_DEVICE_PROFILE_ID_COLUMN; | 48 | import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_DEVICE_PROFILE_ID_COLUMN; |
49 | import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_FILE_NAME_COLUMN; | 49 | import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_FILE_NAME_COLUMN; |
50 | import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_TABLE_NAME; | 50 | import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_TABLE_NAME; |
51 | +import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_TAG_COLUMN; | ||
51 | import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_TENANT_ID_COLUMN; | 52 | import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_TENANT_ID_COLUMN; |
52 | import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_TILE_COLUMN; | 53 | import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_TILE_COLUMN; |
53 | import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_TYPE_COLUMN; | 54 | import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_TYPE_COLUMN; |
@@ -78,6 +79,9 @@ public class OtaPackageEntity extends BaseSqlEntity<OtaPackage> implements Searc | @@ -78,6 +79,9 @@ public class OtaPackageEntity extends BaseSqlEntity<OtaPackage> implements Searc | ||
78 | @Column(name = OTA_PACKAGE_VERSION_COLUMN) | 79 | @Column(name = OTA_PACKAGE_VERSION_COLUMN) |
79 | private String version; | 80 | private String version; |
80 | 81 | ||
82 | + @Column(name = OTA_PACKAGE_TAG_COLUMN) | ||
83 | + private String tag; | ||
84 | + | ||
81 | @Column(name = OTA_PACKAGE_URL_COLUMN) | 85 | @Column(name = OTA_PACKAGE_URL_COLUMN) |
82 | private String url; | 86 | private String url; |
83 | 87 | ||
@@ -112,24 +116,25 @@ public class OtaPackageEntity extends BaseSqlEntity<OtaPackage> implements Searc | @@ -112,24 +116,25 @@ public class OtaPackageEntity extends BaseSqlEntity<OtaPackage> implements Searc | ||
112 | super(); | 116 | super(); |
113 | } | 117 | } |
114 | 118 | ||
115 | - public OtaPackageEntity(OtaPackage firmware) { | ||
116 | - this.createdTime = firmware.getCreatedTime(); | ||
117 | - this.setUuid(firmware.getUuidId()); | ||
118 | - this.tenantId = firmware.getTenantId().getId(); | ||
119 | - if (firmware.getDeviceProfileId() != null) { | ||
120 | - this.deviceProfileId = firmware.getDeviceProfileId().getId(); | 119 | + public OtaPackageEntity(OtaPackage otaPackage) { |
120 | + this.createdTime = otaPackage.getCreatedTime(); | ||
121 | + this.setUuid(otaPackage.getUuidId()); | ||
122 | + this.tenantId = otaPackage.getTenantId().getId(); | ||
123 | + if (otaPackage.getDeviceProfileId() != null) { | ||
124 | + this.deviceProfileId = otaPackage.getDeviceProfileId().getId(); | ||
121 | } | 125 | } |
122 | - this.type = firmware.getType(); | ||
123 | - this.title = firmware.getTitle(); | ||
124 | - this.version = firmware.getVersion(); | ||
125 | - this.url = firmware.getUrl(); | ||
126 | - this.fileName = firmware.getFileName(); | ||
127 | - this.contentType = firmware.getContentType(); | ||
128 | - this.checksumAlgorithm = firmware.getChecksumAlgorithm(); | ||
129 | - this.checksum = firmware.getChecksum(); | ||
130 | - this.data = firmware.getData().array(); | ||
131 | - this.dataSize = firmware.getDataSize(); | ||
132 | - this.additionalInfo = firmware.getAdditionalInfo(); | 126 | + this.type = otaPackage.getType(); |
127 | + this.title = otaPackage.getTitle(); | ||
128 | + this.version = otaPackage.getVersion(); | ||
129 | + this.tag = otaPackage.getTag(); | ||
130 | + this.url = otaPackage.getUrl(); | ||
131 | + this.fileName = otaPackage.getFileName(); | ||
132 | + this.contentType = otaPackage.getContentType(); | ||
133 | + this.checksumAlgorithm = otaPackage.getChecksumAlgorithm(); | ||
134 | + this.checksum = otaPackage.getChecksum(); | ||
135 | + this.data = otaPackage.getData().array(); | ||
136 | + this.dataSize = otaPackage.getDataSize(); | ||
137 | + this.additionalInfo = otaPackage.getAdditionalInfo(); | ||
133 | } | 138 | } |
134 | 139 | ||
135 | @Override | 140 | @Override |
@@ -144,26 +149,27 @@ public class OtaPackageEntity extends BaseSqlEntity<OtaPackage> implements Searc | @@ -144,26 +149,27 @@ public class OtaPackageEntity extends BaseSqlEntity<OtaPackage> implements Searc | ||
144 | 149 | ||
145 | @Override | 150 | @Override |
146 | public OtaPackage toData() { | 151 | public OtaPackage toData() { |
147 | - OtaPackage firmware = new OtaPackage(new OtaPackageId(id)); | ||
148 | - firmware.setCreatedTime(createdTime); | ||
149 | - firmware.setTenantId(new TenantId(tenantId)); | 152 | + OtaPackage otaPackage = new OtaPackage(new OtaPackageId(id)); |
153 | + otaPackage.setCreatedTime(createdTime); | ||
154 | + otaPackage.setTenantId(new TenantId(tenantId)); | ||
150 | if (deviceProfileId != null) { | 155 | if (deviceProfileId != null) { |
151 | - firmware.setDeviceProfileId(new DeviceProfileId(deviceProfileId)); | 156 | + otaPackage.setDeviceProfileId(new DeviceProfileId(deviceProfileId)); |
152 | } | 157 | } |
153 | - firmware.setType(type); | ||
154 | - firmware.setTitle(title); | ||
155 | - firmware.setVersion(version); | ||
156 | - firmware.setUrl(url); | ||
157 | - firmware.setFileName(fileName); | ||
158 | - firmware.setContentType(contentType); | ||
159 | - firmware.setChecksumAlgorithm(checksumAlgorithm); | ||
160 | - firmware.setChecksum(checksum); | ||
161 | - firmware.setDataSize(dataSize); | 158 | + otaPackage.setType(type); |
159 | + otaPackage.setTitle(title); | ||
160 | + otaPackage.setVersion(version); | ||
161 | + otaPackage.setTag(tag); | ||
162 | + otaPackage.setUrl(url); | ||
163 | + otaPackage.setFileName(fileName); | ||
164 | + otaPackage.setContentType(contentType); | ||
165 | + otaPackage.setChecksumAlgorithm(checksumAlgorithm); | ||
166 | + otaPackage.setChecksum(checksum); | ||
167 | + otaPackage.setDataSize(dataSize); | ||
162 | if (data != null) { | 168 | if (data != null) { |
163 | - firmware.setData(ByteBuffer.wrap(data)); | ||
164 | - firmware.setHasData(true); | 169 | + otaPackage.setData(ByteBuffer.wrap(data)); |
170 | + otaPackage.setHasData(true); | ||
165 | } | 171 | } |
166 | - firmware.setAdditionalInfo(additionalInfo); | ||
167 | - return firmware; | 172 | + otaPackage.setAdditionalInfo(additionalInfo); |
173 | + return otaPackage; | ||
168 | } | 174 | } |
169 | } | 175 | } |
@@ -48,6 +48,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_DATA_S | @@ -48,6 +48,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_DATA_S | ||
48 | import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_DEVICE_PROFILE_ID_COLUMN; | 48 | import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_DEVICE_PROFILE_ID_COLUMN; |
49 | import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_FILE_NAME_COLUMN; | 49 | import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_FILE_NAME_COLUMN; |
50 | import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_TABLE_NAME; | 50 | import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_TABLE_NAME; |
51 | +import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_TAG_COLUMN; | ||
51 | import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_TENANT_ID_COLUMN; | 52 | import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_TENANT_ID_COLUMN; |
52 | import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_TILE_COLUMN; | 53 | import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_TILE_COLUMN; |
53 | import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_TYPE_COLUMN; | 54 | import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_TYPE_COLUMN; |
@@ -78,6 +79,9 @@ public class OtaPackageInfoEntity extends BaseSqlEntity<OtaPackageInfo> implemen | @@ -78,6 +79,9 @@ public class OtaPackageInfoEntity extends BaseSqlEntity<OtaPackageInfo> implemen | ||
78 | @Column(name = OTA_PACKAGE_VERSION_COLUMN) | 79 | @Column(name = OTA_PACKAGE_VERSION_COLUMN) |
79 | private String version; | 80 | private String version; |
80 | 81 | ||
82 | + @Column(name = OTA_PACKAGE_TAG_COLUMN) | ||
83 | + private String tag; | ||
84 | + | ||
81 | @Column(name = OTA_PACKAGE_URL_COLUMN) | 85 | @Column(name = OTA_PACKAGE_URL_COLUMN) |
82 | private String url; | 86 | private String url; |
83 | 87 | ||
@@ -111,26 +115,27 @@ public class OtaPackageInfoEntity extends BaseSqlEntity<OtaPackageInfo> implemen | @@ -111,26 +115,27 @@ public class OtaPackageInfoEntity extends BaseSqlEntity<OtaPackageInfo> implemen | ||
111 | super(); | 115 | super(); |
112 | } | 116 | } |
113 | 117 | ||
114 | - public OtaPackageInfoEntity(OtaPackageInfo firmware) { | ||
115 | - this.createdTime = firmware.getCreatedTime(); | ||
116 | - this.setUuid(firmware.getUuidId()); | ||
117 | - this.tenantId = firmware.getTenantId().getId(); | ||
118 | - this.type = firmware.getType(); | ||
119 | - if (firmware.getDeviceProfileId() != null) { | ||
120 | - this.deviceProfileId = firmware.getDeviceProfileId().getId(); | 118 | + public OtaPackageInfoEntity(OtaPackageInfo otaPackageInfo) { |
119 | + this.createdTime = otaPackageInfo.getCreatedTime(); | ||
120 | + this.setUuid(otaPackageInfo.getUuidId()); | ||
121 | + this.tenantId = otaPackageInfo.getTenantId().getId(); | ||
122 | + this.type = otaPackageInfo.getType(); | ||
123 | + if (otaPackageInfo.getDeviceProfileId() != null) { | ||
124 | + this.deviceProfileId = otaPackageInfo.getDeviceProfileId().getId(); | ||
121 | } | 125 | } |
122 | - this.title = firmware.getTitle(); | ||
123 | - this.version = firmware.getVersion(); | ||
124 | - this.url = firmware.getUrl(); | ||
125 | - this.fileName = firmware.getFileName(); | ||
126 | - this.contentType = firmware.getContentType(); | ||
127 | - this.checksumAlgorithm = firmware.getChecksumAlgorithm(); | ||
128 | - this.checksum = firmware.getChecksum(); | ||
129 | - this.dataSize = firmware.getDataSize(); | ||
130 | - this.additionalInfo = firmware.getAdditionalInfo(); | 126 | + this.title = otaPackageInfo.getTitle(); |
127 | + this.version = otaPackageInfo.getVersion(); | ||
128 | + this.tag = otaPackageInfo.getTag(); | ||
129 | + this.url = otaPackageInfo.getUrl(); | ||
130 | + this.fileName = otaPackageInfo.getFileName(); | ||
131 | + this.contentType = otaPackageInfo.getContentType(); | ||
132 | + this.checksumAlgorithm = otaPackageInfo.getChecksumAlgorithm(); | ||
133 | + this.checksum = otaPackageInfo.getChecksum(); | ||
134 | + this.dataSize = otaPackageInfo.getDataSize(); | ||
135 | + this.additionalInfo = otaPackageInfo.getAdditionalInfo(); | ||
131 | } | 136 | } |
132 | 137 | ||
133 | - public OtaPackageInfoEntity(UUID id, long createdTime, UUID tenantId, UUID deviceProfileId, OtaPackageType type, String title, String version, | 138 | + public OtaPackageInfoEntity(UUID id, long createdTime, UUID tenantId, UUID deviceProfileId, OtaPackageType type, String title, String version, String tag, |
134 | String url, String fileName, String contentType, ChecksumAlgorithm checksumAlgorithm, String checksum, Long dataSize, | 139 | String url, String fileName, String contentType, ChecksumAlgorithm checksumAlgorithm, String checksum, Long dataSize, |
135 | Object additionalInfo, boolean hasData) { | 140 | Object additionalInfo, boolean hasData) { |
136 | this.id = id; | 141 | this.id = id; |
@@ -140,6 +145,7 @@ public class OtaPackageInfoEntity extends BaseSqlEntity<OtaPackageInfo> implemen | @@ -140,6 +145,7 @@ public class OtaPackageInfoEntity extends BaseSqlEntity<OtaPackageInfo> implemen | ||
140 | this.type = type; | 145 | this.type = type; |
141 | this.title = title; | 146 | this.title = title; |
142 | this.version = version; | 147 | this.version = version; |
148 | + this.tag = tag; | ||
143 | this.url = url; | 149 | this.url = url; |
144 | this.fileName = fileName; | 150 | this.fileName = fileName; |
145 | this.contentType = contentType; | 151 | this.contentType = contentType; |
@@ -162,23 +168,24 @@ public class OtaPackageInfoEntity extends BaseSqlEntity<OtaPackageInfo> implemen | @@ -162,23 +168,24 @@ public class OtaPackageInfoEntity extends BaseSqlEntity<OtaPackageInfo> implemen | ||
162 | 168 | ||
163 | @Override | 169 | @Override |
164 | public OtaPackageInfo toData() { | 170 | public OtaPackageInfo toData() { |
165 | - OtaPackageInfo firmware = new OtaPackageInfo(new OtaPackageId(id)); | ||
166 | - firmware.setCreatedTime(createdTime); | ||
167 | - firmware.setTenantId(new TenantId(tenantId)); | 171 | + OtaPackageInfo otaPackageInfo = new OtaPackageInfo(new OtaPackageId(id)); |
172 | + otaPackageInfo.setCreatedTime(createdTime); | ||
173 | + otaPackageInfo.setTenantId(new TenantId(tenantId)); | ||
168 | if (deviceProfileId != null) { | 174 | if (deviceProfileId != null) { |
169 | - firmware.setDeviceProfileId(new DeviceProfileId(deviceProfileId)); | 175 | + otaPackageInfo.setDeviceProfileId(new DeviceProfileId(deviceProfileId)); |
170 | } | 176 | } |
171 | - firmware.setType(type); | ||
172 | - firmware.setTitle(title); | ||
173 | - firmware.setVersion(version); | ||
174 | - firmware.setUrl(url); | ||
175 | - firmware.setFileName(fileName); | ||
176 | - firmware.setContentType(contentType); | ||
177 | - firmware.setChecksumAlgorithm(checksumAlgorithm); | ||
178 | - firmware.setChecksum(checksum); | ||
179 | - firmware.setDataSize(dataSize); | ||
180 | - firmware.setAdditionalInfo(additionalInfo); | ||
181 | - firmware.setHasData(hasData); | ||
182 | - return firmware; | 177 | + otaPackageInfo.setType(type); |
178 | + otaPackageInfo.setTitle(title); | ||
179 | + otaPackageInfo.setVersion(version); | ||
180 | + otaPackageInfo.setTag(tag); | ||
181 | + otaPackageInfo.setUrl(url); | ||
182 | + otaPackageInfo.setFileName(fileName); | ||
183 | + otaPackageInfo.setContentType(contentType); | ||
184 | + otaPackageInfo.setChecksumAlgorithm(checksumAlgorithm); | ||
185 | + otaPackageInfo.setChecksum(checksum); | ||
186 | + otaPackageInfo.setDataSize(dataSize); | ||
187 | + otaPackageInfo.setAdditionalInfo(additionalInfo); | ||
188 | + otaPackageInfo.setHasData(hasData); | ||
189 | + return otaPackageInfo; | ||
183 | } | 190 | } |
184 | } | 191 | } |
@@ -51,6 +51,7 @@ import org.thingsboard.server.dao.tenant.TenantDao; | @@ -51,6 +51,7 @@ import org.thingsboard.server.dao.tenant.TenantDao; | ||
51 | import java.nio.ByteBuffer; | 51 | import java.nio.ByteBuffer; |
52 | import java.util.Collections; | 52 | import java.util.Collections; |
53 | import java.util.List; | 53 | import java.util.List; |
54 | +import java.util.Objects; | ||
54 | import java.util.Optional; | 55 | import java.util.Optional; |
55 | 56 | ||
56 | import static org.thingsboard.server.common.data.CacheConstants.OTA_PACKAGE_CACHE; | 57 | import static org.thingsboard.server.common.data.CacheConstants.OTA_PACKAGE_CACHE; |
@@ -318,6 +319,10 @@ public class BaseOtaPackageService implements OtaPackageService { | @@ -318,6 +319,10 @@ public class BaseOtaPackageService implements OtaPackageService { | ||
318 | throw new DataValidationException("Updating otaPackage version is prohibited!"); | 319 | throw new DataValidationException("Updating otaPackage version is prohibited!"); |
319 | } | 320 | } |
320 | 321 | ||
322 | + if (!Objects.equals(otaPackage.getTag(), otaPackageOld.getTag())) { | ||
323 | + throw new DataValidationException("Updating otaPackage tag is prohibited!"); | ||
324 | + } | ||
325 | + | ||
321 | if (!otaPackageOld.getDeviceProfileId().equals(otaPackage.getDeviceProfileId())) { | 326 | if (!otaPackageOld.getDeviceProfileId().equals(otaPackage.getDeviceProfileId())) { |
322 | throw new DataValidationException("Updating otaPackage deviceProfile is prohibited!"); | 327 | throw new DataValidationException("Updating otaPackage deviceProfile is prohibited!"); |
323 | } | 328 | } |
@@ -26,14 +26,14 @@ import org.thingsboard.server.dao.model.sql.OtaPackageInfoEntity; | @@ -26,14 +26,14 @@ import org.thingsboard.server.dao.model.sql.OtaPackageInfoEntity; | ||
26 | import java.util.UUID; | 26 | import java.util.UUID; |
27 | 27 | ||
28 | public interface OtaPackageInfoRepository extends CrudRepository<OtaPackageInfoEntity, UUID> { | 28 | public interface OtaPackageInfoRepository extends CrudRepository<OtaPackageInfoEntity, UUID> { |
29 | - @Query("SELECT new OtaPackageInfoEntity(f.id, f.createdTime, f.tenantId, f.deviceProfileId, f.type, f.title, f.version, f.url, f.fileName, f.contentType, f.checksumAlgorithm, f.checksum, f.dataSize, f.additionalInfo, CASE WHEN (f.data IS NOT NULL OR f.url IS NOT NULL) THEN true ELSE false END) FROM OtaPackageEntity f WHERE " + | 29 | + @Query("SELECT new OtaPackageInfoEntity(f.id, f.createdTime, f.tenantId, f.deviceProfileId, f.type, f.title, f.version, f.tag, f.url, f.fileName, f.contentType, f.checksumAlgorithm, f.checksum, f.dataSize, f.additionalInfo, CASE WHEN (f.data IS NOT NULL OR f.url IS NOT NULL) THEN true ELSE false END) FROM OtaPackageEntity f WHERE " + |
30 | "f.tenantId = :tenantId " + | 30 | "f.tenantId = :tenantId " + |
31 | "AND LOWER(f.searchText) LIKE LOWER(CONCAT(:searchText, '%'))") | 31 | "AND LOWER(f.searchText) LIKE LOWER(CONCAT(:searchText, '%'))") |
32 | Page<OtaPackageInfoEntity> findAllByTenantId(@Param("tenantId") UUID tenantId, | 32 | Page<OtaPackageInfoEntity> findAllByTenantId(@Param("tenantId") UUID tenantId, |
33 | @Param("searchText") String searchText, | 33 | @Param("searchText") String searchText, |
34 | Pageable pageable); | 34 | Pageable pageable); |
35 | 35 | ||
36 | - @Query("SELECT new OtaPackageInfoEntity(f.id, f.createdTime, f.tenantId, f.deviceProfileId, f.type, f.title, f.version, f.url, f.fileName, f.contentType, f.checksumAlgorithm, f.checksum, f.dataSize, f.additionalInfo, true) FROM OtaPackageEntity f WHERE " + | 36 | + @Query("SELECT new OtaPackageInfoEntity(f.id, f.createdTime, f.tenantId, f.deviceProfileId, f.type, f.title, f.version, f.tag, f.url, f.fileName, f.contentType, f.checksumAlgorithm, f.checksum, f.dataSize, f.additionalInfo, true) FROM OtaPackageEntity f WHERE " + |
37 | "f.tenantId = :tenantId " + | 37 | "f.tenantId = :tenantId " + |
38 | "AND f.deviceProfileId = :deviceProfileId " + | 38 | "AND f.deviceProfileId = :deviceProfileId " + |
39 | "AND f.type = :type " + | 39 | "AND f.type = :type " + |
@@ -45,7 +45,7 @@ public interface OtaPackageInfoRepository extends CrudRepository<OtaPackageInfoE | @@ -45,7 +45,7 @@ public interface OtaPackageInfoRepository extends CrudRepository<OtaPackageInfoE | ||
45 | @Param("searchText") String searchText, | 45 | @Param("searchText") String searchText, |
46 | Pageable pageable); | 46 | Pageable pageable); |
47 | 47 | ||
48 | - @Query("SELECT new OtaPackageInfoEntity(f.id, f.createdTime, f.tenantId, f.deviceProfileId, f.type, f.title, f.version, f.url, f.fileName, f.contentType, f.checksumAlgorithm, f.checksum, f.dataSize, f.additionalInfo, CASE WHEN (f.data IS NOT NULL OR f.url IS NOT NULL) THEN true ELSE false END) FROM OtaPackageEntity f WHERE f.id = :id") | 48 | + @Query("SELECT new OtaPackageInfoEntity(f.id, f.createdTime, f.tenantId, f.deviceProfileId, f.type, f.title, f.version, f.tag, f.url, f.fileName, f.contentType, f.checksumAlgorithm, f.checksum, f.dataSize, f.additionalInfo, CASE WHEN (f.data IS NOT NULL OR f.url IS NOT NULL) THEN true ELSE false END) FROM OtaPackageEntity f WHERE f.id = :id") |
49 | OtaPackageInfoEntity findOtaPackageInfoById(@Param("id") UUID id); | 49 | OtaPackageInfoEntity findOtaPackageInfoById(@Param("id") UUID id); |
50 | 50 | ||
51 | @Query(value = "SELECT exists(SELECT * " + | 51 | @Query(value = "SELECT exists(SELECT * " + |
@@ -173,6 +173,7 @@ CREATE TABLE IF NOT EXISTS ota_package ( | @@ -173,6 +173,7 @@ CREATE TABLE IF NOT EXISTS ota_package ( | ||
173 | type varchar(32) NOT NULL, | 173 | type varchar(32) NOT NULL, |
174 | title varchar(255) NOT NULL, | 174 | title varchar(255) NOT NULL, |
175 | version varchar(255) NOT NULL, | 175 | version varchar(255) NOT NULL, |
176 | + tag varchar(255), | ||
176 | url varchar(255), | 177 | url varchar(255), |
177 | file_name varchar(255), | 178 | file_name varchar(255), |
178 | content_type varchar(255), | 179 | content_type varchar(255), |
@@ -188,6 +188,7 @@ CREATE TABLE IF NOT EXISTS ota_package ( | @@ -188,6 +188,7 @@ CREATE TABLE IF NOT EXISTS ota_package ( | ||
188 | type varchar(32) NOT NULL, | 188 | type varchar(32) NOT NULL, |
189 | title varchar(255) NOT NULL, | 189 | title varchar(255) NOT NULL, |
190 | version varchar(255) NOT NULL, | 190 | version varchar(255) NOT NULL, |
191 | + tag varchar(255), | ||
191 | url varchar(255), | 192 | url varchar(255), |
192 | file_name varchar(255), | 193 | file_name varchar(255), |
193 | content_type varchar(255), | 194 | content_type varchar(255), |
@@ -59,9 +59,10 @@ export class OtaUpdateTableConfigResolve implements Resolve<EntityTableConfig<Ot | @@ -59,9 +59,10 @@ export class OtaUpdateTableConfigResolve implements Resolve<EntityTableConfig<Ot | ||
59 | 59 | ||
60 | this.config.columns.push( | 60 | this.config.columns.push( |
61 | new DateEntityTableColumn<OtaPackageInfo>('createdTime', 'common.created-time', this.datePipe, '150px'), | 61 | new DateEntityTableColumn<OtaPackageInfo>('createdTime', 'common.created-time', this.datePipe, '150px'), |
62 | - new EntityTableColumn<OtaPackageInfo>('title', 'ota-update.title', '20%'), | ||
63 | - new EntityTableColumn<OtaPackageInfo>('version', 'ota-update.version', '20%'), | ||
64 | - new EntityTableColumn<OtaPackageInfo>('type', 'ota-update.package-type', '20%', entity => { | 62 | + new EntityTableColumn<OtaPackageInfo>('title', 'ota-update.title', '15%'), |
63 | + new EntityTableColumn<OtaPackageInfo>('version', 'ota-update.version', '15%'), | ||
64 | + new EntityTableColumn<OtaPackageInfo>('tag', 'ota-update.version-tag', '15%'), | ||
65 | + new EntityTableColumn<OtaPackageInfo>('type', 'ota-update.package-type', '15%', entity => { | ||
65 | return this.translate.instant(OtaUpdateTypeTranslationMap.get(entity.type)); | 66 | return this.translate.instant(OtaUpdateTypeTranslationMap.get(entity.type)); |
66 | }), | 67 | }), |
67 | new EntityTableColumn<OtaPackageInfo>('url', 'ota-update.direct-url', '20%', entity => { | 68 | new EntityTableColumn<OtaPackageInfo>('url', 'ota-update.direct-url', '20%', entity => { |
@@ -74,6 +74,11 @@ | @@ -74,6 +74,11 @@ | ||
74 | </mat-error> | 74 | </mat-error> |
75 | </mat-form-field> | 75 | </mat-form-field> |
76 | </div> | 76 | </div> |
77 | + <mat-form-field class="mat-block" fxFlex style="margin-bottom: 8px"> | ||
78 | + <mat-label translate>ota-update.version-tag</mat-label> | ||
79 | + <input matInput formControlName="tag" type="text" [readonly]="!isAdd"> | ||
80 | + <mat-hint *ngIf="isAdd" translate>ota-update.version-tag-hint</mat-hint> | ||
81 | + </mat-form-field> | ||
77 | <tb-device-profile-autocomplete | 82 | <tb-device-profile-autocomplete |
78 | formControlName="deviceProfileId" | 83 | formControlName="deviceProfileId" |
79 | required | 84 | required |
@@ -94,8 +99,8 @@ | @@ -94,8 +99,8 @@ | ||
94 | <section *ngIf="isAdd"> | 99 | <section *ngIf="isAdd"> |
95 | <div class="mat-caption" style="margin: -8px 0 8px;" translate>ota-update.warning-after-save-no-edit</div> | 100 | <div class="mat-caption" style="margin: -8px 0 8px;" translate>ota-update.warning-after-save-no-edit</div> |
96 | <mat-radio-group formControlName="isURL" fxLayoutGap="16px"> | 101 | <mat-radio-group formControlName="isURL" fxLayoutGap="16px"> |
97 | - <mat-radio-button [value]="false">Upload binary file</mat-radio-button> | ||
98 | - <mat-radio-button [value]="true">Use external URL</mat-radio-button> | 102 | + <mat-radio-button [value]="false">{{ "ota-update.upload-binary-file" | translate }}</mat-radio-button> |
103 | + <mat-radio-button [value]="true">{{ "ota-update.use-external-url" | translate }}</mat-radio-button> | ||
99 | </mat-radio-group> | 104 | </mat-radio-group> |
100 | </section> | 105 | </section> |
101 | <section *ngIf="!entityForm.get('isURL').value"> | 106 | <section *ngIf="!entityForm.get('isURL').value"> |
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | /// | 15 | /// |
16 | 16 | ||
17 | import { Component, Inject, OnDestroy, OnInit } from '@angular/core'; | 17 | import { Component, Inject, OnDestroy, OnInit } from '@angular/core'; |
18 | -import { Subject } from 'rxjs'; | 18 | +import { combineLatest, Subject } from 'rxjs'; |
19 | import { Store } from '@ngrx/store'; | 19 | import { Store } from '@ngrx/store'; |
20 | import { AppState } from '@core/core.state'; | 20 | import { AppState } from '@core/core.state'; |
21 | import { TranslateService } from '@ngx-translate/core'; | 21 | import { TranslateService } from '@ngx-translate/core'; |
@@ -30,7 +30,7 @@ import { | @@ -30,7 +30,7 @@ import { | ||
30 | OtaUpdateTypeTranslationMap | 30 | OtaUpdateTypeTranslationMap |
31 | } from '@shared/models/ota-package.models'; | 31 | } from '@shared/models/ota-package.models'; |
32 | import { ActionNotificationShow } from '@core/notification/notification.actions'; | 32 | import { ActionNotificationShow } from '@core/notification/notification.actions'; |
33 | -import { filter, takeUntil } from 'rxjs/operators'; | 33 | +import { filter, startWith, takeUntil } from 'rxjs/operators'; |
34 | import { isNotEmptyStr } from '@core/utils'; | 34 | import { isNotEmptyStr } from '@core/utils'; |
35 | 35 | ||
36 | @Component({ | 36 | @Component({ |
@@ -56,22 +56,33 @@ export class OtaUpdateComponent extends EntityComponent<OtaPackage> implements O | @@ -56,22 +56,33 @@ export class OtaUpdateComponent extends EntityComponent<OtaPackage> implements O | ||
56 | 56 | ||
57 | ngOnInit() { | 57 | ngOnInit() { |
58 | super.ngOnInit(); | 58 | super.ngOnInit(); |
59 | - this.entityForm.get('isURL').valueChanges.pipe( | ||
60 | - filter(() => this.isAdd), | ||
61 | - takeUntil(this.destroy$) | ||
62 | - ).subscribe((isURL) => { | ||
63 | - if (isURL === false) { | ||
64 | - this.entityForm.get('url').clearValidators(); | ||
65 | - this.entityForm.get('file').setValidators(Validators.required); | ||
66 | - this.entityForm.get('url').updateValueAndValidity({emitEvent: false}); | ||
67 | - this.entityForm.get('file').updateValueAndValidity({emitEvent: false}); | ||
68 | - } else { | ||
69 | - this.entityForm.get('file').clearValidators(); | ||
70 | - this.entityForm.get('url').setValidators([Validators.required, Validators.pattern('(.|\\s)*\\S(.|\\s)*')]); | ||
71 | - this.entityForm.get('file').updateValueAndValidity({emitEvent: false}); | ||
72 | - this.entityForm.get('url').updateValueAndValidity({emitEvent: false}); | ||
73 | - } | ||
74 | - }); | 59 | + if (this.isAdd) { |
60 | + this.entityForm.get('isURL').valueChanges.pipe( | ||
61 | + takeUntil(this.destroy$) | ||
62 | + ).subscribe((isURL) => { | ||
63 | + if (isURL === false) { | ||
64 | + this.entityForm.get('url').clearValidators(); | ||
65 | + this.entityForm.get('file').setValidators(Validators.required); | ||
66 | + this.entityForm.get('url').updateValueAndValidity({emitEvent: false}); | ||
67 | + this.entityForm.get('file').updateValueAndValidity({emitEvent: false}); | ||
68 | + } else { | ||
69 | + this.entityForm.get('file').clearValidators(); | ||
70 | + this.entityForm.get('url').setValidators([Validators.required, Validators.pattern('(.|\\s)*\\S(.|\\s)*')]); | ||
71 | + this.entityForm.get('file').updateValueAndValidity({emitEvent: false}); | ||
72 | + this.entityForm.get('url').updateValueAndValidity({emitEvent: false}); | ||
73 | + } | ||
74 | + }); | ||
75 | + combineLatest([ | ||
76 | + this.entityForm.get('title').valueChanges.pipe(startWith('')), | ||
77 | + this.entityForm.get('version').valueChanges.pipe(startWith('')) | ||
78 | + ]).pipe( | ||
79 | + filter(() => this.entityForm.get('tag').pristine), | ||
80 | + takeUntil(this.destroy$) | ||
81 | + ).subscribe(([title, version]) => { | ||
82 | + const tag = (`${title} ${version}`).trim(); | ||
83 | + this.entityForm.get('tag').patchValue(tag); | ||
84 | + }); | ||
85 | + } | ||
75 | } | 86 | } |
76 | 87 | ||
77 | ngOnDestroy() { | 88 | ngOnDestroy() { |
@@ -92,6 +103,7 @@ export class OtaUpdateComponent extends EntityComponent<OtaPackage> implements O | @@ -92,6 +103,7 @@ export class OtaUpdateComponent extends EntityComponent<OtaPackage> implements O | ||
92 | const form = this.fb.group({ | 103 | const form = this.fb.group({ |
93 | title: [entity ? entity.title : '', [Validators.required, Validators.maxLength(255)]], | 104 | title: [entity ? entity.title : '', [Validators.required, Validators.maxLength(255)]], |
94 | version: [entity ? entity.version : '', [Validators.required, Validators.maxLength(255)]], | 105 | version: [entity ? entity.version : '', [Validators.required, Validators.maxLength(255)]], |
106 | + tag: [entity ? entity.tag : '', [Validators.maxLength(255)]], | ||
95 | type: [entity?.type ? entity.type : OtaUpdateType.FIRMWARE, Validators.required], | 107 | type: [entity?.type ? entity.type : OtaUpdateType.FIRMWARE, Validators.required], |
96 | deviceProfileId: [entity ? entity.deviceProfileId : null, Validators.required], | 108 | deviceProfileId: [entity ? entity.deviceProfileId : null, Validators.required], |
97 | checksumAlgorithm: [entity && entity.checksumAlgorithm ? entity.checksumAlgorithm : ChecksumAlgorithm.SHA256], | 109 | checksumAlgorithm: [entity && entity.checksumAlgorithm ? entity.checksumAlgorithm : ChecksumAlgorithm.SHA256], |
@@ -119,6 +131,7 @@ export class OtaUpdateComponent extends EntityComponent<OtaPackage> implements O | @@ -119,6 +131,7 @@ export class OtaUpdateComponent extends EntityComponent<OtaPackage> implements O | ||
119 | this.entityForm.patchValue({ | 131 | this.entityForm.patchValue({ |
120 | title: entity.title, | 132 | title: entity.title, |
121 | version: entity.version, | 133 | version: entity.version, |
134 | + tag: entity.tag, | ||
122 | type: entity.type, | 135 | type: entity.type, |
123 | deviceProfileId: entity.deviceProfileId, | 136 | deviceProfileId: entity.deviceProfileId, |
124 | checksumAlgorithm: entity.checksumAlgorithm, | 137 | checksumAlgorithm: entity.checksumAlgorithm, |
@@ -91,6 +91,7 @@ export interface OtaPackageInfo extends BaseData<OtaPackageId> { | @@ -91,6 +91,7 @@ export interface OtaPackageInfo extends BaseData<OtaPackageId> { | ||
91 | deviceProfileId?: DeviceProfileId; | 91 | deviceProfileId?: DeviceProfileId; |
92 | title?: string; | 92 | title?: string; |
93 | version?: string; | 93 | version?: string; |
94 | + tag?: string; | ||
94 | hasData?: boolean; | 95 | hasData?: boolean; |
95 | url?: string; | 96 | url?: string; |
96 | fileName: string; | 97 | fileName: string; |
@@ -2341,8 +2341,12 @@ | @@ -2341,8 +2341,12 @@ | ||
2341 | "firmware": "Firmware", | 2341 | "firmware": "Firmware", |
2342 | "software": "Software" | 2342 | "software": "Software" |
2343 | }, | 2343 | }, |
2344 | + "upload-binary-file": "Upload binary file", | ||
2345 | + "use-external-url": "Use external URL", | ||
2344 | "version": "Version", | 2346 | "version": "Version", |
2345 | "version-required": "Version is required.", | 2347 | "version-required": "Version is required.", |
2348 | + "version-tag": "Version Tag", | ||
2349 | + "version-tag-hint": "Custom tag should match the package version reported by your device.", | ||
2346 | "warning-after-save-no-edit": "Once the package is uploaded, you will not be able to modify title, version, device profile and package type." | 2350 | "warning-after-save-no-edit": "Once the package is uploaded, you will not be able to modify title, version, device profile and package type." |
2347 | }, | 2351 | }, |
2348 | "position": { | 2352 | "position": { |