Commit 5ca0e05ab57ae1c0aead5a1956bd16a3f80f1d73

Authored by Andrew Shvayka
Committed by GitHub
2 parents 069a51c0 00bd26f1

Merge pull request #4524 from thingsboard/feature/sota

FOTA/SOTA
Showing 66 changed files with 1239 additions and 263 deletions
@@ -63,6 +63,8 @@ CREATE TABLE IF NOT EXISTS firmware ( @@ -63,6 +63,8 @@ CREATE TABLE IF NOT EXISTS firmware (
63 id uuid NOT NULL CONSTRAINT firmware_pkey PRIMARY KEY, 63 id uuid NOT NULL CONSTRAINT firmware_pkey PRIMARY KEY,
64 created_time bigint NOT NULL, 64 created_time bigint NOT NULL,
65 tenant_id uuid NOT NULL, 65 tenant_id uuid NOT NULL,
  66 + device_profile_id uuid,
  67 + type varchar(32) NOT NULL,
66 title varchar(255) NOT NULL, 68 title varchar(255) NOT NULL,
67 version varchar(255) NOT NULL, 69 version varchar(255) NOT NULL,
68 file_name varchar(255), 70 file_name varchar(255),
@@ -77,10 +79,12 @@ CREATE TABLE IF NOT EXISTS firmware ( @@ -77,10 +79,12 @@ CREATE TABLE IF NOT EXISTS firmware (
77 ); 79 );
78 80
79 ALTER TABLE device_profile 81 ALTER TABLE device_profile
80 - ADD COLUMN IF NOT EXISTS firmware_id uuid; 82 + ADD COLUMN IF NOT EXISTS firmware_id uuid,
  83 + ADD COLUMN IF NOT EXISTS software_id uuid;
81 84
82 ALTER TABLE device 85 ALTER TABLE device
83 - ADD COLUMN IF NOT EXISTS firmware_id uuid; 86 + ADD COLUMN IF NOT EXISTS firmware_id uuid,
  87 + ADD COLUMN IF NOT EXISTS software_id uuid;
84 88
85 DO $$ 89 DO $$
86 BEGIN 90 BEGIN
@@ -90,11 +94,23 @@ DO $$ @@ -90,11 +94,23 @@ DO $$
90 FOREIGN KEY (firmware_id) REFERENCES firmware(id); 94 FOREIGN KEY (firmware_id) REFERENCES firmware(id);
91 END IF; 95 END IF;
92 96
  97 + IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_software_device_profile') THEN
  98 + ALTER TABLE device_profile
  99 + ADD CONSTRAINT fk_software_device_profile
  100 + FOREIGN KEY (firmware_id) REFERENCES firmware(id);
  101 + END IF;
  102 +
93 IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_firmware_device') THEN 103 IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_firmware_device') THEN
94 ALTER TABLE device 104 ALTER TABLE device
95 ADD CONSTRAINT fk_firmware_device 105 ADD CONSTRAINT fk_firmware_device
96 FOREIGN KEY (firmware_id) REFERENCES firmware(id); 106 FOREIGN KEY (firmware_id) REFERENCES firmware(id);
97 END IF; 107 END IF;
  108 +
  109 + IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_software_device') THEN
  110 + ALTER TABLE device
  111 + ADD CONSTRAINT fk_software_device
  112 + FOREIGN KEY (firmware_id) REFERENCES firmware(id);
  113 + END IF;
98 END; 114 END;
99 $$; 115 $$;
100 116
@@ -146,12 +146,16 @@ public class DeviceProfileController extends BaseController { @@ -146,12 +146,16 @@ public class DeviceProfileController extends BaseController {
146 checkEntity(deviceProfile.getId(), deviceProfile, Resource.DEVICE_PROFILE); 146 checkEntity(deviceProfile.getId(), deviceProfile, Resource.DEVICE_PROFILE);
147 147
148 boolean isFirmwareChanged = false; 148 boolean isFirmwareChanged = false;
  149 + boolean isSoftwareChanged = false;
149 150
150 if (!created) { 151 if (!created) {
151 DeviceProfile oldDeviceProfile = deviceProfileService.findDeviceProfileById(getTenantId(), deviceProfile.getId()); 152 DeviceProfile oldDeviceProfile = deviceProfileService.findDeviceProfileById(getTenantId(), deviceProfile.getId());
152 if (!Objects.equals(deviceProfile.getFirmwareId(), oldDeviceProfile.getFirmwareId())) { 153 if (!Objects.equals(deviceProfile.getFirmwareId(), oldDeviceProfile.getFirmwareId())) {
153 isFirmwareChanged = true; 154 isFirmwareChanged = true;
154 } 155 }
  156 + if (!Objects.equals(deviceProfile.getSoftwareId(), oldDeviceProfile.getSoftwareId())) {
  157 + isSoftwareChanged = true;
  158 + }
155 } 159 }
156 160
157 DeviceProfile savedDeviceProfile = checkNotNull(deviceProfileService.saveDeviceProfile(deviceProfile)); 161 DeviceProfile savedDeviceProfile = checkNotNull(deviceProfileService.saveDeviceProfile(deviceProfile));
@@ -164,9 +168,8 @@ public class DeviceProfileController extends BaseController { @@ -164,9 +168,8 @@ public class DeviceProfileController extends BaseController {
164 null, 168 null,
165 created ? ActionType.ADDED : ActionType.UPDATED, null); 169 created ? ActionType.ADDED : ActionType.UPDATED, null);
166 170
167 - if (isFirmwareChanged) {  
168 - firmwareStateService.update(savedDeviceProfile);  
169 - } 171 + firmwareStateService.update(savedDeviceProfile, isFirmwareChanged, isSoftwareChanged);
  172 +
170 sendEntityNotificationMsg(getTenantId(), savedDeviceProfile.getId(), 173 sendEntityNotificationMsg(getTenantId(), savedDeviceProfile.getId(),
171 deviceProfile.getId() == null ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED); 174 deviceProfile.getId() == null ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED);
172 return savedDeviceProfile; 175 return savedDeviceProfile;
@@ -35,6 +35,8 @@ import org.thingsboard.server.common.data.Firmware; @@ -35,6 +35,8 @@ import org.thingsboard.server.common.data.Firmware;
35 import org.thingsboard.server.common.data.FirmwareInfo; 35 import org.thingsboard.server.common.data.FirmwareInfo;
36 import org.thingsboard.server.common.data.audit.ActionType; 36 import org.thingsboard.server.common.data.audit.ActionType;
37 import org.thingsboard.server.common.data.exception.ThingsboardException; 37 import org.thingsboard.server.common.data.exception.ThingsboardException;
  38 +import org.thingsboard.server.common.data.firmware.FirmwareType;
  39 +import org.thingsboard.server.common.data.id.DeviceProfileId;
38 import org.thingsboard.server.common.data.id.FirmwareId; 40 import org.thingsboard.server.common.data.id.FirmwareId;
39 import org.thingsboard.server.common.data.page.PageData; 41 import org.thingsboard.server.common.data.page.PageData;
40 import org.thingsboard.server.common.data.page.PageLink; 42 import org.thingsboard.server.common.data.page.PageLink;
@@ -133,6 +135,8 @@ public class FirmwareController extends BaseController { @@ -133,6 +135,8 @@ public class FirmwareController extends BaseController {
133 Firmware firmware = new Firmware(firmwareId); 135 Firmware firmware = new Firmware(firmwareId);
134 firmware.setCreatedTime(info.getCreatedTime()); 136 firmware.setCreatedTime(info.getCreatedTime());
135 firmware.setTenantId(getTenantId()); 137 firmware.setTenantId(getTenantId());
  138 + firmware.setDeviceProfileId(info.getDeviceProfileId());
  139 + firmware.setType(info.getType());
136 firmware.setTitle(info.getTitle()); 140 firmware.setTitle(info.getTitle());
137 firmware.setVersion(info.getVersion()); 141 firmware.setVersion(info.getVersion());
138 firmware.setAdditionalInfo(info.getAdditionalInfo()); 142 firmware.setAdditionalInfo(info.getAdditionalInfo());
@@ -175,17 +179,22 @@ public class FirmwareController extends BaseController { @@ -175,17 +179,22 @@ public class FirmwareController extends BaseController {
175 } 179 }
176 180
177 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") 181 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
178 - @RequestMapping(value = "/firmwares/{hasData}", method = RequestMethod.GET) 182 + @RequestMapping(value = "/firmwares/{deviceProfileId}/{type}/{hasData}", method = RequestMethod.GET)
179 @ResponseBody 183 @ResponseBody
180 - public PageData<FirmwareInfo> getFirmwares(@PathVariable("hasData") boolean hasData, 184 + public PageData<FirmwareInfo> getFirmwares(@PathVariable("deviceProfileId") String strDeviceProfileId,
  185 + @PathVariable("type") String strType,
  186 + @PathVariable("hasData") boolean hasData,
181 @RequestParam int pageSize, 187 @RequestParam int pageSize,
182 @RequestParam int page, 188 @RequestParam int page,
183 @RequestParam(required = false) String textSearch, 189 @RequestParam(required = false) String textSearch,
184 @RequestParam(required = false) String sortProperty, 190 @RequestParam(required = false) String sortProperty,
185 @RequestParam(required = false) String sortOrder) throws ThingsboardException { 191 @RequestParam(required = false) String sortOrder) throws ThingsboardException {
  192 + checkParameter("deviceProfileId", strDeviceProfileId);
  193 + checkParameter("type", strType);
186 try { 194 try {
187 PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); 195 PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
188 - return checkNotNull(firmwareService.findTenantFirmwaresByTenantIdAndHasData(getTenantId(), hasData, pageLink)); 196 + return checkNotNull(firmwareService.findTenantFirmwaresByTenantIdAndDeviceProfileIdAndTypeAndHasData(getTenantId(),
  197 + new DeviceProfileId(toUUID(strDeviceProfileId)), FirmwareType.valueOf(strType), hasData, pageLink));
189 } catch (Exception e) { 198 } catch (Exception e) {
190 throw handleException(e); 199 throw handleException(e);
191 } 200 }
@@ -19,13 +19,17 @@ import com.google.common.util.concurrent.FutureCallback; @@ -19,13 +19,17 @@ import com.google.common.util.concurrent.FutureCallback;
19 import lombok.extern.slf4j.Slf4j; 19 import lombok.extern.slf4j.Slf4j;
20 import org.springframework.stereotype.Service; 20 import org.springframework.stereotype.Service;
21 import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; 21 import org.thingsboard.rule.engine.api.RuleEngineTelemetryService;
  22 +import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg;
22 import org.thingsboard.server.common.data.DataConstants; 23 import org.thingsboard.server.common.data.DataConstants;
23 import org.thingsboard.server.common.data.Device; 24 import org.thingsboard.server.common.data.Device;
24 import org.thingsboard.server.common.data.DeviceProfile; 25 import org.thingsboard.server.common.data.DeviceProfile;
25 import org.thingsboard.server.common.data.FirmwareInfo; 26 import org.thingsboard.server.common.data.FirmwareInfo;
  27 +import org.thingsboard.server.common.data.firmware.FirmwareUtil;
  28 +import org.thingsboard.server.common.data.firmware.FirmwareType;
26 import org.thingsboard.server.common.data.id.DeviceId; 29 import org.thingsboard.server.common.data.id.DeviceId;
27 import org.thingsboard.server.common.data.id.FirmwareId; 30 import org.thingsboard.server.common.data.id.FirmwareId;
28 import org.thingsboard.server.common.data.id.TenantId; 31 import org.thingsboard.server.common.data.id.TenantId;
  32 +import org.thingsboard.server.common.data.kv.AttributeKey;
29 import org.thingsboard.server.common.data.kv.AttributeKvEntry; 33 import org.thingsboard.server.common.data.kv.AttributeKvEntry;
30 import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; 34 import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
31 import org.thingsboard.server.common.data.kv.BasicTsKvEntry; 35 import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
@@ -43,37 +47,49 @@ import org.thingsboard.server.queue.TbQueueProducer; @@ -43,37 +47,49 @@ import org.thingsboard.server.queue.TbQueueProducer;
43 import org.thingsboard.server.queue.common.TbProtoQueueMsg; 47 import org.thingsboard.server.queue.common.TbProtoQueueMsg;
44 import org.thingsboard.server.queue.provider.TbCoreQueueFactory; 48 import org.thingsboard.server.queue.provider.TbCoreQueueFactory;
45 import org.thingsboard.server.queue.util.TbCoreComponent; 49 import org.thingsboard.server.queue.util.TbCoreComponent;
  50 +import org.thingsboard.server.service.queue.TbClusterService;
46 51
47 import javax.annotation.Nullable; 52 import javax.annotation.Nullable;
48 import java.util.ArrayList; 53 import java.util.ArrayList;
49 -import java.util.Arrays;  
50 import java.util.Collections; 54 import java.util.Collections;
  55 +import java.util.HashSet;
51 import java.util.List; 56 import java.util.List;
  57 +import java.util.Set;
52 import java.util.UUID; 58 import java.util.UUID;
53 import java.util.function.Consumer; 59 import java.util.function.Consumer;
54 -  
55 -import static org.thingsboard.server.common.data.DataConstants.FIRMWARE_CHECKSUM;  
56 -import static org.thingsboard.server.common.data.DataConstants.FIRMWARE_CHECKSUM_ALGORITHM;  
57 -import static org.thingsboard.server.common.data.DataConstants.FIRMWARE_SIZE;  
58 -import static org.thingsboard.server.common.data.DataConstants.FIRMWARE_TITLE;  
59 -import static org.thingsboard.server.common.data.DataConstants.FIRMWARE_VERSION; 60 +import java.util.function.Function;
  61 +
  62 +import static org.thingsboard.server.common.data.firmware.FirmwareKey.CHECKSUM;
  63 +import static org.thingsboard.server.common.data.firmware.FirmwareKey.CHECKSUM_ALGORITHM;
  64 +import static org.thingsboard.server.common.data.firmware.FirmwareKey.SIZE;
  65 +import static org.thingsboard.server.common.data.firmware.FirmwareKey.STATE;
  66 +import static org.thingsboard.server.common.data.firmware.FirmwareKey.TITLE;
  67 +import static org.thingsboard.server.common.data.firmware.FirmwareKey.TS;
  68 +import static org.thingsboard.server.common.data.firmware.FirmwareKey.VERSION;
  69 +import static org.thingsboard.server.common.data.firmware.FirmwareUtil.getAttributeKey;
  70 +import static org.thingsboard.server.common.data.firmware.FirmwareUtil.getTargetTelemetryKey;
  71 +import static org.thingsboard.server.common.data.firmware.FirmwareUtil.getTelemetryKey;
  72 +import static org.thingsboard.server.common.data.firmware.FirmwareType.FIRMWARE;
  73 +import static org.thingsboard.server.common.data.firmware.FirmwareType.SOFTWARE;
60 74
61 @Slf4j 75 @Slf4j
62 @Service 76 @Service
63 @TbCoreComponent 77 @TbCoreComponent
64 public class DefaultFirmwareStateService implements FirmwareStateService { 78 public class DefaultFirmwareStateService implements FirmwareStateService {
65 79
  80 + private final TbClusterService tbClusterService;
66 private final FirmwareService firmwareService; 81 private final FirmwareService firmwareService;
67 private final DeviceService deviceService; 82 private final DeviceService deviceService;
68 private final DeviceProfileService deviceProfileService; 83 private final DeviceProfileService deviceProfileService;
69 private final RuleEngineTelemetryService telemetryService; 84 private final RuleEngineTelemetryService telemetryService;
70 private final TbQueueProducer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> fwStateMsgProducer; 85 private final TbQueueProducer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> fwStateMsgProducer;
71 86
72 - public DefaultFirmwareStateService(FirmwareService firmwareService, 87 + public DefaultFirmwareStateService(TbClusterService tbClusterService, FirmwareService firmwareService,
73 DeviceService deviceService, 88 DeviceService deviceService,
74 DeviceProfileService deviceProfileService, 89 DeviceProfileService deviceProfileService,
75 RuleEngineTelemetryService telemetryService, 90 RuleEngineTelemetryService telemetryService,
76 TbCoreQueueFactory coreQueueFactory) { 91 TbCoreQueueFactory coreQueueFactory) {
  92 + this.tbClusterService = tbClusterService;
77 this.firmwareService = firmwareService; 93 this.firmwareService = firmwareService;
78 this.deviceService = deviceService; 94 this.deviceService = deviceService;
79 this.deviceProfileService = deviceProfileService; 95 this.deviceProfileService = deviceProfileService;
@@ -83,6 +99,11 @@ public class DefaultFirmwareStateService implements FirmwareStateService { @@ -83,6 +99,11 @@ public class DefaultFirmwareStateService implements FirmwareStateService {
83 99
84 @Override 100 @Override
85 public void update(Device device, Device oldDevice) { 101 public void update(Device device, Device oldDevice) {
  102 + updateFirmware(device, oldDevice);
  103 + updateSoftware(device, oldDevice);
  104 + }
  105 +
  106 + private void updateFirmware(Device device, Device oldDevice) {
86 FirmwareId newFirmwareId = device.getFirmwareId(); 107 FirmwareId newFirmwareId = device.getFirmwareId();
87 if (newFirmwareId == null) { 108 if (newFirmwareId == null) {
88 DeviceProfile newDeviceProfile = deviceProfileService.findDeviceProfileById(device.getTenantId(), device.getDeviceProfileId()); 109 DeviceProfile newDeviceProfile = deviceProfileService.findDeviceProfileById(device.getTenantId(), device.getDeviceProfileId());
@@ -97,35 +118,84 @@ public class DefaultFirmwareStateService implements FirmwareStateService { @@ -97,35 +118,84 @@ public class DefaultFirmwareStateService implements FirmwareStateService {
97 } 118 }
98 if (!newFirmwareId.equals(oldFirmwareId)) { 119 if (!newFirmwareId.equals(oldFirmwareId)) {
99 // Device was updated and new firmware is different from previous firmware. 120 // Device was updated and new firmware is different from previous firmware.
100 - send(device.getTenantId(), device.getId(), newFirmwareId, System.currentTimeMillis()); 121 + send(device.getTenantId(), device.getId(), newFirmwareId, System.currentTimeMillis(), FIRMWARE);
101 } 122 }
102 } else { 123 } else {
103 // Device was updated and new firmware is not set. 124 // Device was updated and new firmware is not set.
104 - remove(device); 125 + remove(device, FIRMWARE);
105 } 126 }
106 } else if (newFirmwareId != null) { 127 } else if (newFirmwareId != null) {
107 // Device was created and firmware is defined. 128 // Device was created and firmware is defined.
108 - send(device.getTenantId(), device.getId(), newFirmwareId, System.currentTimeMillis()); 129 + send(device.getTenantId(), device.getId(), newFirmwareId, System.currentTimeMillis(), FIRMWARE);
  130 + }
  131 + }
  132 +
  133 + private void updateSoftware(Device device, Device oldDevice) {
  134 + FirmwareId newSoftwareId = device.getSoftwareId();
  135 + if (newSoftwareId == null) {
  136 + DeviceProfile newDeviceProfile = deviceProfileService.findDeviceProfileById(device.getTenantId(), device.getDeviceProfileId());
  137 + newSoftwareId = newDeviceProfile.getSoftwareId();
  138 + }
  139 + if (oldDevice != null) {
  140 + if (newSoftwareId != null) {
  141 + FirmwareId oldSoftwareId = oldDevice.getSoftwareId();
  142 + if (oldSoftwareId == null) {
  143 + DeviceProfile oldDeviceProfile = deviceProfileService.findDeviceProfileById(oldDevice.getTenantId(), oldDevice.getDeviceProfileId());
  144 + oldSoftwareId = oldDeviceProfile.getSoftwareId();
  145 + }
  146 + if (!newSoftwareId.equals(oldSoftwareId)) {
  147 + // Device was updated and new firmware is different from previous firmware.
  148 + send(device.getTenantId(), device.getId(), newSoftwareId, System.currentTimeMillis(), SOFTWARE);
  149 + }
  150 + } else {
  151 + // Device was updated and new firmware is not set.
  152 + remove(device, SOFTWARE);
  153 + }
  154 + } else if (newSoftwareId != null) {
  155 + // Device was created and firmware is defined.
  156 + send(device.getTenantId(), device.getId(), newSoftwareId, System.currentTimeMillis(), SOFTWARE);
109 } 157 }
110 } 158 }
111 159
112 @Override 160 @Override
113 - public void update(DeviceProfile deviceProfile) { 161 + public void update(DeviceProfile deviceProfile, boolean isFirmwareChanged, boolean isSoftwareChanged) {
114 TenantId tenantId = deviceProfile.getTenantId(); 162 TenantId tenantId = deviceProfile.getTenantId();
115 163
  164 + if (isFirmwareChanged) {
  165 + update(tenantId, deviceProfile, FIRMWARE);
  166 + }
  167 + if (isSoftwareChanged) {
  168 + update(tenantId, deviceProfile, SOFTWARE);
  169 + }
  170 + }
  171 +
  172 + private void update(TenantId tenantId, DeviceProfile deviceProfile, FirmwareType firmwareType) {
  173 + Function<PageLink, PageData<Device>> getDevicesFunction;
116 Consumer<Device> updateConsumer; 174 Consumer<Device> updateConsumer;
  175 +
  176 + switch (firmwareType) {
  177 + case FIRMWARE:
  178 + getDevicesFunction = pl -> deviceService.findDevicesByTenantIdAndTypeAndEmptyFirmware(tenantId, deviceProfile.getName(), pl);
  179 + break;
  180 + case SOFTWARE:
  181 + getDevicesFunction = pl -> deviceService.findDevicesByTenantIdAndTypeAndEmptySoftware(tenantId, deviceProfile.getName(), pl);
  182 + break;
  183 + default:
  184 + log.warn("Unsupported firmware type: [{}]", firmwareType);
  185 + return;
  186 + }
  187 +
117 if (deviceProfile.getFirmwareId() != null) { 188 if (deviceProfile.getFirmwareId() != null) {
118 long ts = System.currentTimeMillis(); 189 long ts = System.currentTimeMillis();
119 - updateConsumer = d -> send(d.getTenantId(), d.getId(), deviceProfile.getFirmwareId(), ts); 190 + updateConsumer = d -> send(d.getTenantId(), d.getId(), deviceProfile.getFirmwareId(), ts, firmwareType);
120 } else { 191 } else {
121 - updateConsumer = this::remove; 192 + updateConsumer = d -> remove(d, firmwareType);
122 } 193 }
123 194
124 PageLink pageLink = new PageLink(100); 195 PageLink pageLink = new PageLink(100);
125 PageData<Device> pageData; 196 PageData<Device> pageData;
126 do { 197 do {
127 - pageData = deviceService.findDevicesByTenantIdAndTypeAndEmptyFirmware(tenantId, deviceProfile.getName(), pageLink);  
128 - 198 + pageData = getDevicesFunction.apply(pageLink);
129 pageData.getData().forEach(updateConsumer); 199 pageData.getData().forEach(updateConsumer);
130 200
131 if (pageData.hasNext()) { 201 if (pageData.hasNext()) {
@@ -140,16 +210,17 @@ public class DefaultFirmwareStateService implements FirmwareStateService { @@ -140,16 +210,17 @@ public class DefaultFirmwareStateService implements FirmwareStateService {
140 FirmwareId targetFirmwareId = new FirmwareId(new UUID(msg.getFirmwareIdMSB(), msg.getFirmwareIdLSB())); 210 FirmwareId targetFirmwareId = new FirmwareId(new UUID(msg.getFirmwareIdMSB(), msg.getFirmwareIdLSB()));
141 DeviceId deviceId = new DeviceId(new UUID(msg.getDeviceIdMSB(), msg.getDeviceIdLSB())); 211 DeviceId deviceId = new DeviceId(new UUID(msg.getDeviceIdMSB(), msg.getDeviceIdLSB()));
142 TenantId tenantId = new TenantId(new UUID(msg.getTenantIdMSB(), msg.getTenantIdLSB())); 212 TenantId tenantId = new TenantId(new UUID(msg.getTenantIdMSB(), msg.getTenantIdLSB()));
  213 + FirmwareType firmwareType = FirmwareType.valueOf(msg.getType());
143 long ts = msg.getTs(); 214 long ts = msg.getTs();
144 215
145 Device device = deviceService.findDeviceById(tenantId, deviceId); 216 Device device = deviceService.findDeviceById(tenantId, deviceId);
146 if (device == null) { 217 if (device == null) {
147 log.warn("[{}] [{}] Device was removed during firmware update msg was queued!", tenantId, deviceId); 218 log.warn("[{}] [{}] Device was removed during firmware update msg was queued!", tenantId, deviceId);
148 } else { 219 } else {
149 - FirmwareId currentFirmwareId = device.getFirmwareId();  
150 - 220 + FirmwareId currentFirmwareId = FirmwareUtil.getFirmwareId(device, firmwareType);
151 if (currentFirmwareId == null) { 221 if (currentFirmwareId == null) {
152 - currentFirmwareId = deviceProfileService.findDeviceProfileById(tenantId, device.getDeviceProfileId()).getFirmwareId(); 222 + DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(tenantId, device.getDeviceProfileId());
  223 + currentFirmwareId = FirmwareUtil.getFirmwareId(deviceProfile, firmwareType);
153 } 224 }
154 225
155 if (targetFirmwareId.equals(currentFirmwareId)) { 226 if (targetFirmwareId.equals(currentFirmwareId)) {
@@ -162,7 +233,7 @@ public class DefaultFirmwareStateService implements FirmwareStateService { @@ -162,7 +233,7 @@ public class DefaultFirmwareStateService implements FirmwareStateService {
162 return isSuccess; 233 return isSuccess;
163 } 234 }
164 235
165 - private void send(TenantId tenantId, DeviceId deviceId, FirmwareId firmwareId, long ts) { 236 + private void send(TenantId tenantId, DeviceId deviceId, FirmwareId firmwareId, long ts, FirmwareType firmwareType) {
166 ToFirmwareStateServiceMsg msg = ToFirmwareStateServiceMsg.newBuilder() 237 ToFirmwareStateServiceMsg msg = ToFirmwareStateServiceMsg.newBuilder()
167 .setTenantIdMSB(tenantId.getId().getMostSignificantBits()) 238 .setTenantIdMSB(tenantId.getId().getMostSignificantBits())
168 .setTenantIdLSB(tenantId.getId().getLeastSignificantBits()) 239 .setTenantIdLSB(tenantId.getId().getLeastSignificantBits())
@@ -170,6 +241,7 @@ public class DefaultFirmwareStateService implements FirmwareStateService { @@ -170,6 +241,7 @@ public class DefaultFirmwareStateService implements FirmwareStateService {
170 .setDeviceIdLSB(deviceId.getId().getLeastSignificantBits()) 241 .setDeviceIdLSB(deviceId.getId().getLeastSignificantBits())
171 .setFirmwareIdMSB(firmwareId.getId().getMostSignificantBits()) 242 .setFirmwareIdMSB(firmwareId.getId().getMostSignificantBits())
172 .setFirmwareIdLSB(firmwareId.getId().getLeastSignificantBits()) 243 .setFirmwareIdLSB(firmwareId.getId().getLeastSignificantBits())
  244 + .setType(firmwareType.name())
173 .setTs(ts) 245 .setTs(ts)
174 .build(); 246 .build();
175 247
@@ -183,10 +255,10 @@ public class DefaultFirmwareStateService implements FirmwareStateService { @@ -183,10 +255,10 @@ public class DefaultFirmwareStateService implements FirmwareStateService {
183 fwStateMsgProducer.send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), msg), null); 255 fwStateMsgProducer.send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), msg), null);
184 256
185 List<TsKvEntry> telemetry = new ArrayList<>(); 257 List<TsKvEntry> telemetry = new ArrayList<>();
186 - telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(DataConstants.TARGET_FIRMWARE_TITLE, firmware.getTitle())));  
187 - telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(DataConstants.TARGET_FIRMWARE_VERSION, firmware.getVersion())));  
188 - telemetry.add(new BasicTsKvEntry(ts, new LongDataEntry(DataConstants.TARGET_FIRMWARE_TS, ts)));  
189 - telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_STATE, FirmwareUpdateStatus.QUEUED.name()))); 258 + telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(getTargetTelemetryKey(firmware.getType(), TITLE), firmware.getTitle())));
  259 + telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(getTargetTelemetryKey(firmware.getType(), VERSION), firmware.getVersion())));
  260 + telemetry.add(new BasicTsKvEntry(ts, new LongDataEntry(getTargetTelemetryKey(firmware.getType(), TS), ts)));
  261 + telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(getTelemetryKey(firmware.getType(), STATE), FirmwareUpdateStatus.QUEUED.name())));
190 262
191 telemetryService.saveAndNotify(tenantId, deviceId, telemetry, new FutureCallback<>() { 263 telemetryService.saveAndNotify(tenantId, deviceId, telemetry, new FutureCallback<>() {
192 @Override 264 @Override
@@ -206,7 +278,7 @@ public class DefaultFirmwareStateService implements FirmwareStateService { @@ -206,7 +278,7 @@ public class DefaultFirmwareStateService implements FirmwareStateService {
206 TenantId tenantId = device.getTenantId(); 278 TenantId tenantId = device.getTenantId();
207 DeviceId deviceId = device.getId(); 279 DeviceId deviceId = device.getId();
208 280
209 - BasicTsKvEntry status = new BasicTsKvEntry(System.currentTimeMillis(), new StringDataEntry(DataConstants.FIRMWARE_STATE, FirmwareUpdateStatus.INITIATED.name())); 281 + BasicTsKvEntry status = new BasicTsKvEntry(System.currentTimeMillis(), new StringDataEntry(getTelemetryKey(firmware.getType(), STATE), FirmwareUpdateStatus.INITIATED.name()));
210 282
211 telemetryService.saveAndNotify(tenantId, deviceId, Collections.singletonList(status), new FutureCallback<>() { 283 telemetryService.saveAndNotify(tenantId, deviceId, Collections.singletonList(status), new FutureCallback<>() {
212 @Override 284 @Override
@@ -221,13 +293,12 @@ public class DefaultFirmwareStateService implements FirmwareStateService { @@ -221,13 +293,12 @@ public class DefaultFirmwareStateService implements FirmwareStateService {
221 }); 293 });
222 294
223 List<AttributeKvEntry> attributes = new ArrayList<>(); 295 List<AttributeKvEntry> attributes = new ArrayList<>();
  296 + attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(getAttributeKey(firmware.getType(), TITLE), firmware.getTitle())));
  297 + attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(getAttributeKey(firmware.getType(), VERSION), firmware.getVersion())));
  298 + attributes.add(new BaseAttributeKvEntry(ts, new LongDataEntry(getAttributeKey(firmware.getType(), SIZE), firmware.getDataSize())));
  299 + attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(getAttributeKey(firmware.getType(), CHECKSUM_ALGORITHM), firmware.getChecksumAlgorithm())));
  300 + attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(getAttributeKey(firmware.getType(), CHECKSUM), firmware.getChecksum())));
224 301
225 - attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_TITLE, firmware.getTitle())));  
226 - attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_VERSION, firmware.getVersion())));  
227 -  
228 - attributes.add(new BaseAttributeKvEntry(ts, new LongDataEntry(FIRMWARE_SIZE, firmware.getDataSize())));  
229 - attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_CHECKSUM_ALGORITHM, firmware.getChecksumAlgorithm())));  
230 - attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_CHECKSUM, firmware.getChecksum())));  
231 telemetryService.saveAndNotify(tenantId, deviceId, DataConstants.SHARED_SCOPE, attributes, new FutureCallback<>() { 302 telemetryService.saveAndNotify(tenantId, deviceId, DataConstants.SHARED_SCOPE, attributes, new FutureCallback<>() {
232 @Override 303 @Override
233 public void onSuccess(@Nullable Void tmp) { 304 public void onSuccess(@Nullable Void tmp) {
@@ -241,13 +312,15 @@ public class DefaultFirmwareStateService implements FirmwareStateService { @@ -241,13 +312,15 @@ public class DefaultFirmwareStateService implements FirmwareStateService {
241 }); 312 });
242 } 313 }
243 314
244 - private void remove(Device device) {  
245 - telemetryService.deleteAndNotify(device.getTenantId(), device.getId(), DataConstants.SHARED_SCOPE,  
246 - Arrays.asList(FIRMWARE_TITLE, FIRMWARE_VERSION, FIRMWARE_SIZE, FIRMWARE_CHECKSUM_ALGORITHM, FIRMWARE_CHECKSUM), 315 + private void remove(Device device, FirmwareType firmwareType) {
  316 + telemetryService.deleteAndNotify(device.getTenantId(), device.getId(), DataConstants.SHARED_SCOPE, FirmwareUtil.getAttributeKeys(firmwareType),
247 new FutureCallback<>() { 317 new FutureCallback<>() {
248 @Override 318 @Override
249 public void onSuccess(@Nullable Void tmp) { 319 public void onSuccess(@Nullable Void tmp) {
250 log.trace("[{}] Success remove target firmware attributes!", device.getId()); 320 log.trace("[{}] Success remove target firmware attributes!", device.getId());
  321 + Set<AttributeKey> keysToNotify = new HashSet<>();
  322 + FirmwareUtil.ALL_FW_ATTRIBUTE_KEYS.forEach(key -> keysToNotify.add(new AttributeKey(DataConstants.SHARED_SCOPE, key)));
  323 + tbClusterService.pushMsgToCore(DeviceAttributesEventNotificationMsg.onDelete(device.getTenantId(), device.getId(), keysToNotify), null);
251 } 324 }
252 325
253 @Override 326 @Override
@@ -23,7 +23,7 @@ public interface FirmwareStateService { @@ -23,7 +23,7 @@ public interface FirmwareStateService {
23 23
24 void update(Device device, Device oldDevice); 24 void update(Device device, Device oldDevice);
25 25
26 - void update(DeviceProfile deviceProfile); 26 + void update(DeviceProfile deviceProfile, boolean isFirmwareChanged, boolean isSoftwareChanged);
27 27
28 boolean process(ToFirmwareStateServiceMsg msg); 28 boolean process(ToFirmwareStateServiceMsg msg);
29 29
@@ -41,6 +41,8 @@ import org.thingsboard.server.common.data.TenantProfile; @@ -41,6 +41,8 @@ import org.thingsboard.server.common.data.TenantProfile;
41 import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; 41 import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials;
42 import org.thingsboard.server.common.data.device.credentials.ProvisionDeviceCredentialsData; 42 import org.thingsboard.server.common.data.device.credentials.ProvisionDeviceCredentialsData;
43 import org.thingsboard.server.common.data.device.profile.ProvisionDeviceProfileCredentials; 43 import org.thingsboard.server.common.data.device.profile.ProvisionDeviceProfileCredentials;
  44 +import org.thingsboard.server.common.data.firmware.FirmwareType;
  45 +import org.thingsboard.server.common.data.firmware.FirmwareUtil;
44 import org.thingsboard.server.common.data.id.CustomerId; 46 import org.thingsboard.server.common.data.id.CustomerId;
45 import org.thingsboard.server.common.data.id.DeviceId; 47 import org.thingsboard.server.common.data.id.DeviceId;
46 import org.thingsboard.server.common.data.id.DeviceProfileId; 48 import org.thingsboard.server.common.data.id.DeviceProfileId;
@@ -512,16 +514,17 @@ public class DefaultTransportApiService implements TransportApiService { @@ -512,16 +514,17 @@ public class DefaultTransportApiService implements TransportApiService {
512 private ListenableFuture<TransportApiResponseMsg> handle(TransportProtos.GetFirmwareRequestMsg requestMsg) { 514 private ListenableFuture<TransportApiResponseMsg> handle(TransportProtos.GetFirmwareRequestMsg requestMsg) {
513 TenantId tenantId = new TenantId(new UUID(requestMsg.getTenantIdMSB(), requestMsg.getTenantIdLSB())); 515 TenantId tenantId = new TenantId(new UUID(requestMsg.getTenantIdMSB(), requestMsg.getTenantIdLSB()));
514 DeviceId deviceId = new DeviceId(new UUID(requestMsg.getDeviceIdMSB(), requestMsg.getDeviceIdLSB())); 516 DeviceId deviceId = new DeviceId(new UUID(requestMsg.getDeviceIdMSB(), requestMsg.getDeviceIdLSB()));
  517 + FirmwareType firmwareType = FirmwareType.valueOf(requestMsg.getType());
515 Device device = deviceService.findDeviceById(tenantId, deviceId); 518 Device device = deviceService.findDeviceById(tenantId, deviceId);
516 519
517 if (device == null) { 520 if (device == null) {
518 return getEmptyTransportApiResponseFuture(); 521 return getEmptyTransportApiResponseFuture();
519 } 522 }
520 523
521 - FirmwareId firmwareId = device.getFirmwareId();  
522 - 524 + FirmwareId firmwareId = FirmwareUtil.getFirmwareId(device, firmwareType);
523 if (firmwareId == null) { 525 if (firmwareId == null) {
524 - firmwareId = deviceProfileCache.find(device.getDeviceProfileId()).getFirmwareId(); 526 + DeviceProfile deviceProfile = deviceProfileCache.find(device.getDeviceProfileId());
  527 + firmwareId = FirmwareUtil.getFirmwareId(deviceProfile, firmwareType);
525 } 528 }
526 529
527 TransportProtos.GetFirmwareResponseMsg.Builder builder = TransportProtos.GetFirmwareResponseMsg.newBuilder(); 530 TransportProtos.GetFirmwareResponseMsg.Builder builder = TransportProtos.GetFirmwareResponseMsg.newBuilder();
@@ -537,6 +540,7 @@ public class DefaultTransportApiService implements TransportApiService { @@ -537,6 +540,7 @@ public class DefaultTransportApiService implements TransportApiService {
537 builder.setResponseStatus(TransportProtos.ResponseStatus.SUCCESS); 540 builder.setResponseStatus(TransportProtos.ResponseStatus.SUCCESS);
538 builder.setFirmwareIdMSB(firmwareId.getId().getMostSignificantBits()); 541 builder.setFirmwareIdMSB(firmwareId.getId().getMostSignificantBits());
539 builder.setFirmwareIdLSB(firmwareId.getId().getLeastSignificantBits()); 542 builder.setFirmwareIdLSB(firmwareId.getId().getLeastSignificantBits());
  543 + builder.setType(firmwareInfo.getType().name());
540 builder.setTitle(firmwareInfo.getTitle()); 544 builder.setTitle(firmwareInfo.getTitle());
541 builder.setVersion(firmwareInfo.getVersion()); 545 builder.setVersion(firmwareInfo.getVersion());
542 builder.setFileName(firmwareInfo.getFileName()); 546 builder.setFileName(firmwareInfo.getFileName());
@@ -24,10 +24,13 @@ import org.springframework.mock.web.MockMultipartFile; @@ -24,10 +24,13 @@ import org.springframework.mock.web.MockMultipartFile;
24 import org.springframework.test.web.servlet.request.MockMultipartHttpServletRequestBuilder; 24 import org.springframework.test.web.servlet.request.MockMultipartHttpServletRequestBuilder;
25 import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; 25 import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
26 import org.thingsboard.common.util.JacksonUtil; 26 import org.thingsboard.common.util.JacksonUtil;
  27 +import org.thingsboard.server.common.data.DeviceProfile;
27 import org.thingsboard.server.common.data.Firmware; 28 import org.thingsboard.server.common.data.Firmware;
28 import org.thingsboard.server.common.data.FirmwareInfo; 29 import org.thingsboard.server.common.data.FirmwareInfo;
29 import org.thingsboard.server.common.data.Tenant; 30 import org.thingsboard.server.common.data.Tenant;
30 import org.thingsboard.server.common.data.User; 31 import org.thingsboard.server.common.data.User;
  32 +import org.thingsboard.server.common.data.firmware.FirmwareType;
  33 +import org.thingsboard.server.common.data.id.DeviceProfileId;
31 import org.thingsboard.server.common.data.page.PageData; 34 import org.thingsboard.server.common.data.page.PageData;
32 import org.thingsboard.server.common.data.page.PageLink; 35 import org.thingsboard.server.common.data.page.PageLink;
33 import org.thingsboard.server.common.data.security.Authority; 36 import org.thingsboard.server.common.data.security.Authority;
@@ -38,6 +41,7 @@ import java.util.Collections; @@ -38,6 +41,7 @@ import java.util.Collections;
38 import java.util.List; 41 import java.util.List;
39 42
40 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 43 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
  44 +import static org.thingsboard.server.common.data.firmware.FirmwareType.FIRMWARE;
41 45
42 public abstract class BaseFirmwareControllerTest extends AbstractControllerTest { 46 public abstract class BaseFirmwareControllerTest extends AbstractControllerTest {
43 47
@@ -53,6 +57,7 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest @@ -53,6 +57,7 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest
53 57
54 private Tenant savedTenant; 58 private Tenant savedTenant;
55 private User tenantAdmin; 59 private User tenantAdmin;
  60 + private DeviceProfileId deviceProfileId;
56 61
57 @Before 62 @Before
58 public void beforeTest() throws Exception { 63 public void beforeTest() throws Exception {
@@ -71,6 +76,11 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest @@ -71,6 +76,11 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest
71 tenantAdmin.setLastName("Downs"); 76 tenantAdmin.setLastName("Downs");
72 77
73 tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); 78 tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
  79 +
  80 + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null);
  81 + DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
  82 + Assert.assertNotNull(savedDeviceProfile);
  83 + deviceProfileId = savedDeviceProfile.getId();
74 } 84 }
75 85
76 @After 86 @After
@@ -84,6 +94,8 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest @@ -84,6 +94,8 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest
84 @Test 94 @Test
85 public void testSaveFirmware() throws Exception { 95 public void testSaveFirmware() throws Exception {
86 FirmwareInfo firmwareInfo = new FirmwareInfo(); 96 FirmwareInfo firmwareInfo = new FirmwareInfo();
  97 + firmwareInfo.setDeviceProfileId(deviceProfileId);
  98 + firmwareInfo.setType(FIRMWARE);
87 firmwareInfo.setTitle(TITLE); 99 firmwareInfo.setTitle(TITLE);
88 firmwareInfo.setVersion(VERSION); 100 firmwareInfo.setVersion(VERSION);
89 101
@@ -107,6 +119,8 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest @@ -107,6 +119,8 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest
107 @Test 119 @Test
108 public void testSaveFirmwareData() throws Exception { 120 public void testSaveFirmwareData() throws Exception {
109 FirmwareInfo firmwareInfo = new FirmwareInfo(); 121 FirmwareInfo firmwareInfo = new FirmwareInfo();
  122 + firmwareInfo.setDeviceProfileId(deviceProfileId);
  123 + firmwareInfo.setType(FIRMWARE);
110 firmwareInfo.setTitle(TITLE); 124 firmwareInfo.setTitle(TITLE);
111 firmwareInfo.setVersion(VERSION); 125 firmwareInfo.setVersion(VERSION);
112 126
@@ -137,6 +151,8 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest @@ -137,6 +151,8 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest
137 @Test 151 @Test
138 public void testUpdateFirmwareFromDifferentTenant() throws Exception { 152 public void testUpdateFirmwareFromDifferentTenant() throws Exception {
139 FirmwareInfo firmwareInfo = new FirmwareInfo(); 153 FirmwareInfo firmwareInfo = new FirmwareInfo();
  154 + firmwareInfo.setDeviceProfileId(deviceProfileId);
  155 + firmwareInfo.setType(FIRMWARE);
140 firmwareInfo.setTitle(TITLE); 156 firmwareInfo.setTitle(TITLE);
141 firmwareInfo.setVersion(VERSION); 157 firmwareInfo.setVersion(VERSION);
142 158
@@ -150,6 +166,8 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest @@ -150,6 +166,8 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest
150 @Test 166 @Test
151 public void testFindFirmwareInfoById() throws Exception { 167 public void testFindFirmwareInfoById() throws Exception {
152 FirmwareInfo firmwareInfo = new FirmwareInfo(); 168 FirmwareInfo firmwareInfo = new FirmwareInfo();
  169 + firmwareInfo.setDeviceProfileId(deviceProfileId);
  170 + firmwareInfo.setType(FIRMWARE);
153 firmwareInfo.setTitle(TITLE); 171 firmwareInfo.setTitle(TITLE);
154 firmwareInfo.setVersion(VERSION); 172 firmwareInfo.setVersion(VERSION);
155 173
@@ -163,6 +181,8 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest @@ -163,6 +181,8 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest
163 @Test 181 @Test
164 public void testFindFirmwareById() throws Exception { 182 public void testFindFirmwareById() throws Exception {
165 FirmwareInfo firmwareInfo = new FirmwareInfo(); 183 FirmwareInfo firmwareInfo = new FirmwareInfo();
  184 + firmwareInfo.setDeviceProfileId(deviceProfileId);
  185 + firmwareInfo.setType(FIRMWARE);
166 firmwareInfo.setTitle(TITLE); 186 firmwareInfo.setTitle(TITLE);
167 firmwareInfo.setVersion(VERSION); 187 firmwareInfo.setVersion(VERSION);
168 188
@@ -180,6 +200,8 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest @@ -180,6 +200,8 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest
180 @Test 200 @Test
181 public void testDeleteFirmware() throws Exception { 201 public void testDeleteFirmware() throws Exception {
182 FirmwareInfo firmwareInfo = new FirmwareInfo(); 202 FirmwareInfo firmwareInfo = new FirmwareInfo();
  203 + firmwareInfo.setDeviceProfileId(deviceProfileId);
  204 + firmwareInfo.setType(FIRMWARE);
183 firmwareInfo.setTitle(TITLE); 205 firmwareInfo.setTitle(TITLE);
184 firmwareInfo.setVersion(VERSION); 206 firmwareInfo.setVersion(VERSION);
185 207
@@ -197,6 +219,8 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest @@ -197,6 +219,8 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest
197 List<FirmwareInfo> firmwares = new ArrayList<>(); 219 List<FirmwareInfo> firmwares = new ArrayList<>();
198 for (int i = 0; i < 165; i++) { 220 for (int i = 0; i < 165; i++) {
199 FirmwareInfo firmwareInfo = new FirmwareInfo(); 221 FirmwareInfo firmwareInfo = new FirmwareInfo();
  222 + firmwareInfo.setDeviceProfileId(deviceProfileId);
  223 + firmwareInfo.setType(FIRMWARE);
200 firmwareInfo.setTitle(TITLE); 224 firmwareInfo.setTitle(TITLE);
201 firmwareInfo.setVersion(VERSION + i); 225 firmwareInfo.setVersion(VERSION + i);
202 226
@@ -238,6 +262,8 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest @@ -238,6 +262,8 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest
238 262
239 for (int i = 0; i < 165; i++) { 263 for (int i = 0; i < 165; i++) {
240 FirmwareInfo firmwareInfo = new FirmwareInfo(); 264 FirmwareInfo firmwareInfo = new FirmwareInfo();
  265 + firmwareInfo.setDeviceProfileId(deviceProfileId);
  266 + firmwareInfo.setType(FIRMWARE);
241 firmwareInfo.setTitle(TITLE); 267 firmwareInfo.setTitle(TITLE);
242 firmwareInfo.setVersion(VERSION + i); 268 firmwareInfo.setVersion(VERSION + i);
243 269
@@ -257,7 +283,7 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest @@ -257,7 +283,7 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest
257 PageLink pageLink = new PageLink(24); 283 PageLink pageLink = new PageLink(24);
258 PageData<FirmwareInfo> pageData; 284 PageData<FirmwareInfo> pageData;
259 do { 285 do {
260 - pageData = doGetTypedWithPageLink("/api/firmwares/true?", 286 + pageData = doGetTypedWithPageLink("/api/firmwares/" + deviceProfileId.toString() + "/FIRMWARE/true?",
261 new TypeReference<>() { 287 new TypeReference<>() {
262 }, pageLink); 288 }, pageLink);
263 loadedFirmwaresWithData.addAll(pageData.getData()); 289 loadedFirmwaresWithData.addAll(pageData.getData());
@@ -269,7 +295,7 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest @@ -269,7 +295,7 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest
269 List<FirmwareInfo> loadedFirmwaresWithoutData = new ArrayList<>(); 295 List<FirmwareInfo> loadedFirmwaresWithoutData = new ArrayList<>();
270 pageLink = new PageLink(24); 296 pageLink = new PageLink(24);
271 do { 297 do {
272 - pageData = doGetTypedWithPageLink("/api/firmwares/false?", 298 + pageData = doGetTypedWithPageLink("/api/firmwares/" + deviceProfileId.toString() + "/FIRMWARE/false?",
273 new TypeReference<>() { 299 new TypeReference<>() {
274 }, pageLink); 300 }, pageLink);
275 loadedFirmwaresWithoutData.addAll(pageData.getData()); 301 loadedFirmwaresWithoutData.addAll(pageData.getData());
@@ -65,6 +65,8 @@ public interface DeviceService { @@ -65,6 +65,8 @@ public interface DeviceService {
65 65
66 PageData<Device> findDevicesByTenantIdAndTypeAndEmptyFirmware(TenantId tenantId, String type, PageLink pageLink); 66 PageData<Device> findDevicesByTenantIdAndTypeAndEmptyFirmware(TenantId tenantId, String type, PageLink pageLink);
67 67
  68 + PageData<Device> findDevicesByTenantIdAndTypeAndEmptySoftware(TenantId tenantId, String type, PageLink pageLink);
  69 +
68 PageData<DeviceInfo> findDeviceInfosByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink); 70 PageData<DeviceInfo> findDeviceInfosByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink);
69 71
70 PageData<DeviceInfo> findDeviceInfosByTenantIdAndDeviceProfileId(TenantId tenantId, DeviceProfileId deviceProfileId, PageLink pageLink); 72 PageData<DeviceInfo> findDeviceInfosByTenantIdAndDeviceProfileId(TenantId tenantId, DeviceProfileId deviceProfileId, PageLink pageLink);
@@ -18,6 +18,8 @@ package org.thingsboard.server.dao.firmware; @@ -18,6 +18,8 @@ package org.thingsboard.server.dao.firmware;
18 import com.google.common.util.concurrent.ListenableFuture; 18 import com.google.common.util.concurrent.ListenableFuture;
19 import org.thingsboard.server.common.data.Firmware; 19 import org.thingsboard.server.common.data.Firmware;
20 import org.thingsboard.server.common.data.FirmwareInfo; 20 import org.thingsboard.server.common.data.FirmwareInfo;
  21 +import org.thingsboard.server.common.data.firmware.FirmwareType;
  22 +import org.thingsboard.server.common.data.id.DeviceProfileId;
21 import org.thingsboard.server.common.data.id.FirmwareId; 23 import org.thingsboard.server.common.data.id.FirmwareId;
22 import org.thingsboard.server.common.data.id.TenantId; 24 import org.thingsboard.server.common.data.id.TenantId;
23 import org.thingsboard.server.common.data.page.PageData; 25 import org.thingsboard.server.common.data.page.PageData;
@@ -37,7 +39,7 @@ public interface FirmwareService { @@ -37,7 +39,7 @@ public interface FirmwareService {
37 39
38 PageData<FirmwareInfo> findTenantFirmwaresByTenantId(TenantId tenantId, PageLink pageLink); 40 PageData<FirmwareInfo> findTenantFirmwaresByTenantId(TenantId tenantId, PageLink pageLink);
39 41
40 - PageData<FirmwareInfo> findTenantFirmwaresByTenantIdAndHasData(TenantId tenantId, boolean hasData, PageLink pageLink); 42 + PageData<FirmwareInfo> findTenantFirmwaresByTenantIdAndDeviceProfileIdAndTypeAndHasData(TenantId tenantId, DeviceProfileId deviceProfileId, FirmwareType firmwareType, boolean hasData, PageLink pageLink);
41 43
42 void deleteFirmware(TenantId tenantId, FirmwareId firmwareId); 44 void deleteFirmware(TenantId tenantId, FirmwareId firmwareId);
43 45
@@ -93,22 +93,26 @@ public class DataConstants { @@ -93,22 +93,26 @@ public class DataConstants {
93 public static final String USERNAME = "username"; 93 public static final String USERNAME = "username";
94 public static final String PASSWORD = "password"; 94 public static final String PASSWORD = "password";
95 95
96 - //firmware  
97 - //telemetry  
98 - public static final String CURRENT_FIRMWARE_TITLE = "current_fw_title";  
99 - public static final String CURRENT_FIRMWARE_VERSION = "current_fw_version";  
100 - public static final String TARGET_FIRMWARE_TITLE = "target_fw_title";  
101 - public static final String TARGET_FIRMWARE_VERSION = "target_fw_version";  
102 - public static final String TARGET_FIRMWARE_TS = "target_fw_ts";  
103 - public static final String FIRMWARE_STATE = "fw_state";  
104 -  
105 - //attributes  
106 - //telemetry  
107 - public static final String FIRMWARE_TITLE = "fw_title";  
108 - public static final String FIRMWARE_VERSION = "fw_version";  
109 - public static final String FIRMWARE_SIZE = "fw_size";  
110 - public static final String FIRMWARE_CHECKSUM = "fw_checksum";  
111 - public static final String FIRMWARE_CHECKSUM_ALGORITHM = "fw_checksum_algorithm"; 96 +//<<<<<<< HEAD
  97 +//=======
  98 +// //firmware
  99 +// //telemetry
  100 +// public static final String CURRENT_FIRMWARE_TITLE = "current_fw_title";
  101 +// public static final String CURRENT_FIRMWARE_VERSION = "current_fw_version";
  102 +// public static final String TARGET_FIRMWARE_TITLE = "target_fw_title";
  103 +// public static final String TARGET_FIRMWARE_VERSION = "target_fw_version";
  104 +// public static final String TARGET_FIRMWARE_TS = "target_fw_ts";
  105 +// public static final String FIRMWARE_STATE = "fw_state";
  106 +//
  107 +// //attributes
  108 +// //telemetry
  109 +// public static final String FIRMWARE_TITLE = "fw_title";
  110 +// public static final String FIRMWARE_VERSION = "fw_version";
  111 +// public static final String FIRMWARE_SIZE = "fw_size";
  112 +// public static final String FIRMWARE_CHECKSUM = "fw_checksum";
  113 +// public static final String FIRMWARE_CHECKSUM_ALGORITHM = "fw_checksum_algorithm";
  114 +//>>>>>>> origin/master
112 public static final String EDGE_MSG_SOURCE = "edge"; 115 public static final String EDGE_MSG_SOURCE = "edge";
113 public static final String MSG_SOURCE_KEY = "source"; 116 public static final String MSG_SOURCE_KEY = "source";
  117 +
114 } 118 }
@@ -32,7 +32,7 @@ import java.io.IOException; @@ -32,7 +32,7 @@ import java.io.IOException;
32 32
33 @EqualsAndHashCode(callSuper = true) 33 @EqualsAndHashCode(callSuper = true)
34 @Slf4j 34 @Slf4j
35 -public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implements HasName, HasTenantId, HasCustomerId { 35 +public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implements HasName, HasTenantId, HasCustomerId, HasFirmware {
36 36
37 private static final long serialVersionUID = 2807343040519543363L; 37 private static final long serialVersionUID = 2807343040519543363L;
38 38
@@ -50,6 +50,7 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen @@ -50,6 +50,7 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen
50 private byte[] deviceDataBytes; 50 private byte[] deviceDataBytes;
51 51
52 private FirmwareId firmwareId; 52 private FirmwareId firmwareId;
  53 + private FirmwareId softwareId;
53 54
54 public Device() { 55 public Device() {
55 super(); 56 super();
@@ -69,6 +70,7 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen @@ -69,6 +70,7 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen
69 this.deviceProfileId = device.getDeviceProfileId(); 70 this.deviceProfileId = device.getDeviceProfileId();
70 this.setDeviceData(device.getDeviceData()); 71 this.setDeviceData(device.getDeviceData());
71 this.firmwareId = device.getFirmwareId(); 72 this.firmwareId = device.getFirmwareId();
  73 + this.softwareId = device.getSoftwareId();
72 } 74 }
73 75
74 public Device updateDevice(Device device) { 76 public Device updateDevice(Device device) {
@@ -79,6 +81,8 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen @@ -79,6 +81,8 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen
79 this.label = device.getLabel(); 81 this.label = device.getLabel();
80 this.deviceProfileId = device.getDeviceProfileId(); 82 this.deviceProfileId = device.getDeviceProfileId();
81 this.setDeviceData(device.getDeviceData()); 83 this.setDeviceData(device.getDeviceData());
  84 + this.setFirmwareId(device.getFirmwareId());
  85 + this.setSoftwareId(device.getSoftwareId());
82 return this; 86 return this;
83 } 87 }
84 88
@@ -171,6 +175,14 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen @@ -171,6 +175,14 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen
171 this.firmwareId = firmwareId; 175 this.firmwareId = firmwareId;
172 } 176 }
173 177
  178 + public FirmwareId getSoftwareId() {
  179 + return softwareId;
  180 + }
  181 +
  182 + public void setSoftwareId(FirmwareId softwareId) {
  183 + this.softwareId = softwareId;
  184 + }
  185 +
174 @Override 186 @Override
175 public String toString() { 187 public String toString() {
176 StringBuilder builder = new StringBuilder(); 188 StringBuilder builder = new StringBuilder();
@@ -36,7 +36,7 @@ import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalIn @@ -36,7 +36,7 @@ import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalIn
36 @Data 36 @Data
37 @EqualsAndHashCode(callSuper = true) 37 @EqualsAndHashCode(callSuper = true)
38 @Slf4j 38 @Slf4j
39 -public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements HasName, HasTenantId { 39 +public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements HasName, HasTenantId, HasFirmware {
40 40
41 private TenantId tenantId; 41 private TenantId tenantId;
42 @NoXss 42 @NoXss
@@ -59,6 +59,8 @@ public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements H @@ -59,6 +59,8 @@ public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements H
59 59
60 private FirmwareId firmwareId; 60 private FirmwareId firmwareId;
61 61
  62 + private FirmwareId softwareId;
  63 +
62 public DeviceProfile() { 64 public DeviceProfile() {
63 super(); 65 super();
64 } 66 }
@@ -77,6 +79,8 @@ public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements H @@ -77,6 +79,8 @@ public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements H
77 this.defaultQueueName = deviceProfile.getDefaultQueueName(); 79 this.defaultQueueName = deviceProfile.getDefaultQueueName();
78 this.setProfileData(deviceProfile.getProfileData()); 80 this.setProfileData(deviceProfile.getProfileData());
79 this.provisionDeviceKey = deviceProfile.getProvisionDeviceKey(); 81 this.provisionDeviceKey = deviceProfile.getProvisionDeviceKey();
  82 + this.firmwareId = deviceProfile.getFirmwareId();
  83 + this.softwareId = deviceProfile.getSoftwareId();
80 } 84 }
81 85
82 @Override 86 @Override
@@ -19,6 +19,8 @@ import com.fasterxml.jackson.annotation.JsonIgnore; @@ -19,6 +19,8 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
19 import lombok.Data; 19 import lombok.Data;
20 import lombok.EqualsAndHashCode; 20 import lombok.EqualsAndHashCode;
21 import lombok.extern.slf4j.Slf4j; 21 import lombok.extern.slf4j.Slf4j;
  22 +import org.thingsboard.server.common.data.firmware.FirmwareType;
  23 +import org.thingsboard.server.common.data.id.DeviceProfileId;
22 import org.thingsboard.server.common.data.id.FirmwareId; 24 import org.thingsboard.server.common.data.id.FirmwareId;
23 import org.thingsboard.server.common.data.id.TenantId; 25 import org.thingsboard.server.common.data.id.TenantId;
24 26
@@ -30,6 +32,8 @@ public class FirmwareInfo extends SearchTextBasedWithAdditionalInfo<FirmwareId> @@ -30,6 +32,8 @@ public class FirmwareInfo extends SearchTextBasedWithAdditionalInfo<FirmwareId>
30 private static final long serialVersionUID = 3168391583570815419L; 32 private static final long serialVersionUID = 3168391583570815419L;
31 33
32 private TenantId tenantId; 34 private TenantId tenantId;
  35 + private DeviceProfileId deviceProfileId;
  36 + private FirmwareType type;
33 private String title; 37 private String title;
34 private String version; 38 private String version;
35 private boolean hasData; 39 private boolean hasData;
@@ -51,6 +55,8 @@ public class FirmwareInfo extends SearchTextBasedWithAdditionalInfo<FirmwareId> @@ -51,6 +55,8 @@ public class FirmwareInfo extends SearchTextBasedWithAdditionalInfo<FirmwareId>
51 public FirmwareInfo(FirmwareInfo firmwareInfo) { 55 public FirmwareInfo(FirmwareInfo firmwareInfo) {
52 super(firmwareInfo); 56 super(firmwareInfo);
53 this.tenantId = firmwareInfo.getTenantId(); 57 this.tenantId = firmwareInfo.getTenantId();
  58 + this.deviceProfileId = firmwareInfo.getDeviceProfileId();
  59 + this.type = firmwareInfo.getType();
54 this.title = firmwareInfo.getTitle(); 60 this.title = firmwareInfo.getTitle();
55 this.version = firmwareInfo.getVersion(); 61 this.version = firmwareInfo.getVersion();
56 this.hasData = firmwareInfo.isHasData(); 62 this.hasData = firmwareInfo.isHasData();
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data;
  17 +
  18 +import org.thingsboard.server.common.data.id.FirmwareId;
  19 +
  20 +public interface HasFirmware {
  21 +
  22 + FirmwareId getFirmwareId();
  23 +
  24 + FirmwareId getSoftwareId();
  25 +}
@@ -31,6 +31,7 @@ public class MqttTopics { @@ -31,6 +31,7 @@ public class MqttTopics {
31 private static final String SUB_TOPIC = "+"; 31 private static final String SUB_TOPIC = "+";
32 private static final String PROVISION = "/provision"; 32 private static final String PROVISION = "/provision";
33 private static final String FIRMWARE = "/fw"; 33 private static final String FIRMWARE = "/fw";
  34 + private static final String SOFTWARE = "/sw";
34 private static final String CHUNK = "/chunk/"; 35 private static final String CHUNK = "/chunk/";
35 private static final String ERROR = "/error"; 36 private static final String ERROR = "/error";
36 37
@@ -75,9 +76,17 @@ public class MqttTopics { @@ -75,9 +76,17 @@ public class MqttTopics {
75 // v2 topics 76 // v2 topics
76 public static final String BASE_DEVICE_API_TOPIC_V2 = "v2"; 77 public static final String BASE_DEVICE_API_TOPIC_V2 = "v2";
77 78
78 - public static final String DEVICE_FIRMWARE_RESPONSE_TOPIC_PREFIX = BASE_DEVICE_API_TOPIC_V2 + FIRMWARE + RESPONSE + "/";  
79 - public static final String DEVICE_FIRMWARE_RESPONSES_TOPIC = DEVICE_FIRMWARE_RESPONSE_TOPIC_PREFIX + SUB_TOPIC + CHUNK + SUB_TOPIC; 79 + public static final String REQUEST_ID_PATTERN = "(?<requestId>\\d+)";
  80 + public static final String CHUNK_PATTERN = "(?<chunk>\\d+)";
  81 +
  82 + public static final String DEVICE_FIRMWARE_REQUEST_TOPIC_PATTERN = BASE_DEVICE_API_TOPIC_V2 + FIRMWARE + REQUEST + "/" + REQUEST_ID_PATTERN + CHUNK + CHUNK_PATTERN;
  83 + public static final String DEVICE_FIRMWARE_RESPONSES_TOPIC = BASE_DEVICE_API_TOPIC_V2 + FIRMWARE + RESPONSE + "/" + SUB_TOPIC + CHUNK + SUB_TOPIC;
80 public static final String DEVICE_FIRMWARE_ERROR_TOPIC = BASE_DEVICE_API_TOPIC_V2 + FIRMWARE + ERROR; 84 public static final String DEVICE_FIRMWARE_ERROR_TOPIC = BASE_DEVICE_API_TOPIC_V2 + FIRMWARE + ERROR;
  85 + public static final String DEVICE_FIRMWARE_RESPONSES_TOPIC_FORMAT = BASE_DEVICE_API_TOPIC_V2 + "%s" + RESPONSE + "/"+ "%s" + CHUNK + "%d";
  86 +
  87 + public static final String DEVICE_SOFTWARE_REQUEST_TOPIC_PATTERN = BASE_DEVICE_API_TOPIC_V2 + SOFTWARE + REQUEST + "/" + REQUEST_ID_PATTERN + CHUNK + CHUNK_PATTERN;
  88 + public static final String DEVICE_SOFTWARE_RESPONSES_TOPIC = BASE_DEVICE_API_TOPIC_V2 + SOFTWARE + RESPONSE + "/" + SUB_TOPIC + CHUNK + SUB_TOPIC;
  89 + public static final String DEVICE_SOFTWARE_ERROR_TOPIC = BASE_DEVICE_API_TOPIC_V2 + SOFTWARE + ERROR;
81 90
82 private MqttTopics() { 91 private MqttTopics() {
83 } 92 }
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.firmware;
  17 +
  18 +import lombok.Getter;
  19 +
  20 +public enum FirmwareKey {
  21 +
  22 + TITLE("title"), VERSION("version"), TS("ts"), STATE("state"), SIZE("size"), CHECKSUM("checksum"), CHECKSUM_ALGORITHM("checksum_algorithm");
  23 +
  24 + @Getter
  25 + private final String value;
  26 +
  27 + FirmwareKey(String value) {
  28 + this.value = value;
  29 + }
  30 +}
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.firmware;
  17 +
  18 +import lombok.Getter;
  19 +
  20 +public enum FirmwareType {
  21 +
  22 + FIRMWARE("fw"), SOFTWARE("sw");
  23 +
  24 + @Getter
  25 + private final String keyPrefix;
  26 +
  27 + FirmwareType(String keyPrefix) {
  28 + this.keyPrefix = keyPrefix;
  29 + }
  30 +}
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.firmware;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.thingsboard.server.common.data.HasFirmware;
  20 +import org.thingsboard.server.common.data.id.FirmwareId;
  21 +
  22 +import java.util.ArrayList;
  23 +import java.util.Collections;
  24 +import java.util.List;
  25 +
  26 +import static org.thingsboard.server.common.data.firmware.FirmwareType.FIRMWARE;
  27 +import static org.thingsboard.server.common.data.firmware.FirmwareType.SOFTWARE;
  28 +
  29 +@Slf4j
  30 +public class FirmwareUtil {
  31 +
  32 + public static final List<String> ALL_FW_ATTRIBUTE_KEYS;
  33 +
  34 + public static final List<String> ALL_SW_ATTRIBUTE_KEYS;
  35 +
  36 + static {
  37 + ALL_FW_ATTRIBUTE_KEYS = new ArrayList<>();
  38 + for (FirmwareKey key : FirmwareKey.values()) {
  39 + ALL_FW_ATTRIBUTE_KEYS.add(getAttributeKey(FIRMWARE, key));
  40 +
  41 + }
  42 +
  43 + ALL_SW_ATTRIBUTE_KEYS = new ArrayList<>();
  44 + for (FirmwareKey key : FirmwareKey.values()) {
  45 + ALL_SW_ATTRIBUTE_KEYS.add(getAttributeKey(SOFTWARE, key));
  46 +
  47 + }
  48 + }
  49 +
  50 + public static List<String> getAttributeKeys(FirmwareType firmwareType) {
  51 + switch (firmwareType) {
  52 + case FIRMWARE:
  53 + return ALL_FW_ATTRIBUTE_KEYS;
  54 + case SOFTWARE:
  55 + return ALL_SW_ATTRIBUTE_KEYS;
  56 + }
  57 + return Collections.emptyList();
  58 + }
  59 +
  60 + public static String getAttributeKey(FirmwareType type, FirmwareKey key) {
  61 + return type.getKeyPrefix() + "_" + key.getValue();
  62 + }
  63 +
  64 + public static String getTargetTelemetryKey(FirmwareType type, FirmwareKey key) {
  65 + return getTelemetryKey("target_", type, key);
  66 + }
  67 +
  68 + public static String getCurrentTelemetryKey(FirmwareType type, FirmwareKey key) {
  69 + return getTelemetryKey("current_", type, key);
  70 + }
  71 +
  72 + private static String getTelemetryKey(String prefix, FirmwareType type, FirmwareKey key) {
  73 + return prefix + type.getKeyPrefix() + "_" + key.getValue();
  74 + }
  75 +
  76 + public static String getTelemetryKey(FirmwareType type, FirmwareKey key) {
  77 + return type.getKeyPrefix() + "_" + key.getValue();
  78 + }
  79 +
  80 + public static FirmwareId getFirmwareId(HasFirmware entity, FirmwareType firmwareType) {
  81 + switch (firmwareType) {
  82 + case FIRMWARE:
  83 + return entity.getFirmwareId();
  84 + case SOFTWARE:
  85 + return entity.getSoftwareId();
  86 + default:
  87 + log.warn("Unsupported firmware type: [{}]", firmwareType);
  88 + return null;
  89 + }
  90 + }
  91 +}
@@ -16,5 +16,5 @@ @@ -16,5 +16,5 @@
16 package org.thingsboard.server.common.msg.session; 16 package org.thingsboard.server.common.msg.session;
17 17
18 public enum FeatureType { 18 public enum FeatureType {
19 - ATTRIBUTES, TELEMETRY, RPC, CLAIM, PROVISION, FIRMWARE 19 + ATTRIBUTES, TELEMETRY, RPC, CLAIM, PROVISION, FIRMWARE, SOFTWARE
20 } 20 }
@@ -32,7 +32,8 @@ public enum SessionMsgType { @@ -32,7 +32,8 @@ public enum SessionMsgType {
32 32
33 CLAIM_REQUEST(), 33 CLAIM_REQUEST(),
34 34
35 - GET_FIRMWARE_REQUEST; 35 + GET_FIRMWARE_REQUEST,
  36 + GET_SOFTWARE_REQUEST;
36 37
37 private final boolean requiresRulesProcessing; 38 private final boolean requiresRulesProcessing;
38 39
@@ -388,16 +388,18 @@ message GetFirmwareRequestMsg { @@ -388,16 +388,18 @@ message GetFirmwareRequestMsg {
388 int64 deviceIdLSB = 2; 388 int64 deviceIdLSB = 2;
389 int64 tenantIdMSB = 3; 389 int64 tenantIdMSB = 3;
390 int64 tenantIdLSB = 4; 390 int64 tenantIdLSB = 4;
  391 + string type = 5;
391 } 392 }
392 393
393 message GetFirmwareResponseMsg { 394 message GetFirmwareResponseMsg {
394 ResponseStatus responseStatus = 1; 395 ResponseStatus responseStatus = 1;
395 int64 firmwareIdMSB = 2; 396 int64 firmwareIdMSB = 2;
396 int64 firmwareIdLSB = 3; 397 int64 firmwareIdLSB = 3;
397 - string title = 4;  
398 - string version = 5;  
399 - string contentType = 6;  
400 - string fileName = 7; 398 + string type = 4;
  399 + string title = 5;
  400 + string version = 6;
  401 + string contentType = 7;
  402 + string fileName = 8;
401 } 403 }
402 404
403 //Used to report session state to tb-Service and persist this state in the cache on the tb-Service level. 405 //Used to report session state to tb-Service and persist this state in the cache on the tb-Service level.
@@ -711,4 +713,5 @@ message ToFirmwareStateServiceMsg { @@ -711,4 +713,5 @@ message ToFirmwareStateServiceMsg {
711 int64 deviceIdLSB = 5; 713 int64 deviceIdLSB = 5;
712 int64 firmwareIdMSB = 6; 714 int64 firmwareIdMSB = 6;
713 int64 firmwareIdLSB = 7; 715 int64 firmwareIdLSB = 7;
  716 + string type = 8;
714 } 717 }
@@ -43,6 +43,7 @@ import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportC @@ -43,6 +43,7 @@ import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportC
43 import org.thingsboard.server.common.data.device.profile.JsonTransportPayloadConfiguration; 43 import org.thingsboard.server.common.data.device.profile.JsonTransportPayloadConfiguration;
44 import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration; 44 import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
45 import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; 45 import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
  46 +import org.thingsboard.server.common.data.firmware.FirmwareType;
46 import org.thingsboard.server.common.data.security.DeviceTokenCredentials; 47 import org.thingsboard.server.common.data.security.DeviceTokenCredentials;
47 import org.thingsboard.server.common.msg.session.FeatureType; 48 import org.thingsboard.server.common.msg.session.FeatureType;
48 import org.thingsboard.server.common.msg.session.SessionMsgType; 49 import org.thingsboard.server.common.msg.session.SessionMsgType;
@@ -122,6 +123,8 @@ public class CoapTransportResource extends AbstractCoapTransportResource { @@ -122,6 +123,8 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
122 processRequest(exchange, SessionMsgType.GET_ATTRIBUTES_REQUEST); 123 processRequest(exchange, SessionMsgType.GET_ATTRIBUTES_REQUEST);
123 } else if (featureType.get() == FeatureType.FIRMWARE) { 124 } else if (featureType.get() == FeatureType.FIRMWARE) {
124 processRequest(exchange, SessionMsgType.GET_FIRMWARE_REQUEST); 125 processRequest(exchange, SessionMsgType.GET_FIRMWARE_REQUEST);
  126 + } else if (featureType.get() == FeatureType.SOFTWARE) {
  127 + processRequest(exchange, SessionMsgType.GET_SOFTWARE_REQUEST);
125 } else { 128 } else {
126 log.trace("Invalid feature type parameter"); 129 log.trace("Invalid feature type parameter");
127 exchange.respond(CoAP.ResponseCode.BAD_REQUEST); 130 exchange.respond(CoAP.ResponseCode.BAD_REQUEST);
@@ -326,12 +329,10 @@ public class CoapTransportResource extends AbstractCoapTransportResource { @@ -326,12 +329,10 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
326 new CoapNoOpCallback(exchange)); 329 new CoapNoOpCallback(exchange));
327 break; 330 break;
328 case GET_FIRMWARE_REQUEST: 331 case GET_FIRMWARE_REQUEST:
329 - TransportProtos.GetFirmwareRequestMsg requestMsg = TransportProtos.GetFirmwareRequestMsg.newBuilder()  
330 - .setTenantIdMSB(sessionInfo.getTenantIdMSB())  
331 - .setTenantIdLSB(sessionInfo.getTenantIdLSB())  
332 - .setDeviceIdMSB(sessionInfo.getDeviceIdMSB())  
333 - .setDeviceIdLSB(sessionInfo.getDeviceIdLSB()).build();  
334 - transportContext.getTransportService().process(sessionInfo, requestMsg, new FirmwareCallback(exchange)); 332 + getFirmwareCallback(sessionInfo, exchange, FirmwareType.FIRMWARE);
  333 + break;
  334 + case GET_SOFTWARE_REQUEST:
  335 + getFirmwareCallback(sessionInfo, exchange, FirmwareType.SOFTWARE);
335 break; 336 break;
336 } 337 }
337 } catch (AdaptorException e) { 338 } catch (AdaptorException e) {
@@ -340,6 +341,16 @@ public class CoapTransportResource extends AbstractCoapTransportResource { @@ -340,6 +341,16 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
340 } 341 }
341 } 342 }
342 343
  344 + private void getFirmwareCallback(TransportProtos.SessionInfoProto sessionInfo, CoapExchange exchange, FirmwareType firmwareType) {
  345 + TransportProtos.GetFirmwareRequestMsg requestMsg = TransportProtos.GetFirmwareRequestMsg.newBuilder()
  346 + .setTenantIdMSB(sessionInfo.getTenantIdMSB())
  347 + .setTenantIdLSB(sessionInfo.getTenantIdLSB())
  348 + .setDeviceIdMSB(sessionInfo.getDeviceIdMSB())
  349 + .setDeviceIdLSB(sessionInfo.getDeviceIdLSB())
  350 + .setType(firmwareType.name()).build();
  351 + transportContext.getTransportService().process(sessionInfo, requestMsg, new FirmwareCallback(exchange));
  352 + }
  353 +
343 private TransportProtos.SessionInfoProto lookupAsyncSessionInfo(String token) { 354 private TransportProtos.SessionInfoProto lookupAsyncSessionInfo(String token) {
344 tokenToNotificationCounterMap.remove(token); 355 tokenToNotificationCounterMap.remove(token);
345 return tokenToSessionIdMap.remove(token); 356 return tokenToSessionIdMap.remove(token);
@@ -34,6 +34,7 @@ import org.springframework.web.bind.annotation.RequestParam; @@ -34,6 +34,7 @@ import org.springframework.web.bind.annotation.RequestParam;
34 import org.springframework.web.bind.annotation.RestController; 34 import org.springframework.web.bind.annotation.RestController;
35 import org.springframework.web.context.request.async.DeferredResult; 35 import org.springframework.web.context.request.async.DeferredResult;
36 import org.thingsboard.server.common.data.DeviceTransportType; 36 import org.thingsboard.server.common.data.DeviceTransportType;
  37 +import org.thingsboard.server.common.data.firmware.FirmwareType;
37 import org.thingsboard.server.common.data.TbTransportService; 38 import org.thingsboard.server.common.data.TbTransportService;
38 import org.thingsboard.server.common.data.id.DeviceId; 39 import org.thingsboard.server.common.data.id.DeviceId;
39 import org.thingsboard.server.common.transport.SessionMsgListener; 40 import org.thingsboard.server.common.transport.SessionMsgListener;
@@ -210,8 +211,29 @@ public class DeviceApiController implements TbTransportService { @@ -210,8 +211,29 @@ public class DeviceApiController implements TbTransportService {
210 public DeferredResult<ResponseEntity> getFirmware(@PathVariable("deviceToken") String deviceToken, 211 public DeferredResult<ResponseEntity> getFirmware(@PathVariable("deviceToken") String deviceToken,
211 @RequestParam(value = "title") String title, 212 @RequestParam(value = "title") String title,
212 @RequestParam(value = "version") String version, 213 @RequestParam(value = "version") String version,
213 - @RequestParam(value = "chunkSize", required = false, defaultValue = "0") int chunkSize, 214 + @RequestParam(value = "size", required = false, defaultValue = "0") int size,
214 @RequestParam(value = "chunk", required = false, defaultValue = "0") int chunk) { 215 @RequestParam(value = "chunk", required = false, defaultValue = "0") int chunk) {
  216 + return getFirmwareCallback(deviceToken, title, version, size, chunk, FirmwareType.FIRMWARE);
  217 + }
  218 +
  219 + @RequestMapping(value = "/{deviceToken}/software", method = RequestMethod.GET)
  220 + public DeferredResult<ResponseEntity> getSoftware(@PathVariable("deviceToken") String deviceToken,
  221 + @RequestParam(value = "title") String title,
  222 + @RequestParam(value = "version") String version,
  223 + @RequestParam(value = "size", required = false, defaultValue = "0") int size,
  224 + @RequestParam(value = "chunk", required = false, defaultValue = "0") int chunk) {
  225 + return getFirmwareCallback(deviceToken, title, version, size, chunk, FirmwareType.SOFTWARE);
  226 + }
  227 +
  228 + @RequestMapping(value = "/provision", method = RequestMethod.POST)
  229 + public DeferredResult<ResponseEntity> provisionDevice(@RequestBody String json, HttpServletRequest httpRequest) {
  230 + DeferredResult<ResponseEntity> responseWriter = new DeferredResult<>();
  231 + transportContext.getTransportService().process(JsonConverter.convertToProvisionRequestMsg(json),
  232 + new DeviceProvisionCallback(responseWriter));
  233 + return responseWriter;
  234 + }
  235 +
  236 + private DeferredResult<ResponseEntity> getFirmwareCallback(String deviceToken, String title, String version, int size, int chunk, FirmwareType firmwareType) {
215 DeferredResult<ResponseEntity> responseWriter = new DeferredResult<>(); 237 DeferredResult<ResponseEntity> responseWriter = new DeferredResult<>();
216 transportContext.getTransportService().process(DeviceTransportType.DEFAULT, ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(), 238 transportContext.getTransportService().process(DeviceTransportType.DEFAULT, ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(),
217 new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> { 239 new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> {
@@ -219,20 +241,13 @@ public class DeviceApiController implements TbTransportService { @@ -219,20 +241,13 @@ public class DeviceApiController implements TbTransportService {
219 .setTenantIdMSB(sessionInfo.getTenantIdMSB()) 241 .setTenantIdMSB(sessionInfo.getTenantIdMSB())
220 .setTenantIdLSB(sessionInfo.getTenantIdLSB()) 242 .setTenantIdLSB(sessionInfo.getTenantIdLSB())
221 .setDeviceIdMSB(sessionInfo.getDeviceIdMSB()) 243 .setDeviceIdMSB(sessionInfo.getDeviceIdMSB())
222 - .setDeviceIdLSB(sessionInfo.getDeviceIdLSB()).build();  
223 - transportContext.getTransportService().process(sessionInfo, requestMsg, new GetFirmwareCallback(responseWriter, title, version, chunkSize, chunk)); 244 + .setDeviceIdLSB(sessionInfo.getDeviceIdLSB())
  245 + .setType(firmwareType.name()).build();
  246 + transportContext.getTransportService().process(sessionInfo, requestMsg, new GetFirmwareCallback(responseWriter, title, version, size, chunk));
224 })); 247 }));
225 return responseWriter; 248 return responseWriter;
226 } 249 }
227 250
228 - @RequestMapping(value = "/provision", method = RequestMethod.POST)  
229 - public DeferredResult<ResponseEntity> provisionDevice(@RequestBody String json, HttpServletRequest httpRequest) {  
230 - DeferredResult<ResponseEntity> responseWriter = new DeferredResult<>();  
231 - transportContext.getTransportService().process(JsonConverter.convertToProvisionRequestMsg(json),  
232 - new DeviceProvisionCallback(responseWriter));  
233 - return responseWriter;  
234 - }  
235 -  
236 private static class DeviceAuthCallback implements TransportServiceCallback<ValidateDeviceCredentialsResponse> { 251 private static class DeviceAuthCallback implements TransportServiceCallback<ValidateDeviceCredentialsResponse> {
237 private final TransportContext transportContext; 252 private final TransportContext transportContext;
238 private final DeferredResult<ResponseEntity> responseWriter; 253 private final DeferredResult<ResponseEntity> responseWriter;
@@ -41,6 +41,9 @@ import org.thingsboard.common.util.JacksonUtil; @@ -41,6 +41,9 @@ import org.thingsboard.common.util.JacksonUtil;
41 import org.thingsboard.server.cache.firmware.FirmwareDataCache; 41 import org.thingsboard.server.cache.firmware.FirmwareDataCache;
42 import org.thingsboard.server.common.data.Device; 42 import org.thingsboard.server.common.data.Device;
43 import org.thingsboard.server.common.data.DeviceProfile; 43 import org.thingsboard.server.common.data.DeviceProfile;
  44 +import org.thingsboard.server.common.data.firmware.FirmwareKey;
  45 +import org.thingsboard.server.common.data.firmware.FirmwareType;
  46 +import org.thingsboard.server.common.data.firmware.FirmwareUtil;
44 import org.thingsboard.server.common.data.id.FirmwareId; 47 import org.thingsboard.server.common.data.id.FirmwareId;
45 import org.thingsboard.server.common.transport.TransportService; 48 import org.thingsboard.server.common.transport.TransportService;
46 import org.thingsboard.server.common.transport.TransportServiceCallback; 49 import org.thingsboard.server.common.transport.TransportServiceCallback;
@@ -79,7 +82,6 @@ import java.util.stream.Collectors; @@ -79,7 +82,6 @@ import java.util.stream.Collectors;
79 82
80 import static org.eclipse.californium.core.coap.CoAP.ResponseCode.BAD_REQUEST; 83 import static org.eclipse.californium.core.coap.CoAP.ResponseCode.BAD_REQUEST;
81 import static org.eclipse.leshan.core.attributes.Attribute.OBJECT_VERSION; 84 import static org.eclipse.leshan.core.attributes.Attribute.OBJECT_VERSION;
82 -import static org.thingsboard.server.common.data.DataConstants.FIRMWARE_VERSION;  
83 import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_KEY; 85 import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_KEY;
84 import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; 86 import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
85 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.CLIENT_NOT_AUTHORIZED; 87 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.CLIENT_NOT_AUTHORIZED;
@@ -332,7 +334,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { @@ -332,7 +334,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
332 String pathName = tsKvProto.getKv().getKey(); 334 String pathName = tsKvProto.getKv().getKey();
333 String pathIdVer = this.getPresentPathIntoProfile(sessionInfo, pathName); 335 String pathIdVer = this.getPresentPathIntoProfile(sessionInfo, pathName);
334 Object valueNew = this.lwM2mTransportContextServer.getValueFromKvProto(tsKvProto.getKv()); 336 Object valueNew = this.lwM2mTransportContextServer.getValueFromKvProto(tsKvProto.getKv());
335 - if (FIRMWARE_VERSION.equals(pathName) && !valueNew.equals(lwM2MClient.getFrUpdate().getCurrentFwVersion())) { 337 + if (FirmwareUtil.getAttributeKey(FirmwareType.FIRMWARE, FirmwareKey.VERSION).equals(pathName) && !valueNew.equals(lwM2MClient.getFrUpdate().getCurrentFwVersion())) {
336 this.getInfoFirmwareUpdate(lwM2MClient); 338 this.getInfoFirmwareUpdate(lwM2MClient);
337 } 339 }
338 if (pathIdVer != null) { 340 if (pathIdVer != null) {
@@ -358,7 +360,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { @@ -358,7 +360,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
358 msg.getSharedUpdatedList().forEach(tsKvProto -> { 360 msg.getSharedUpdatedList().forEach(tsKvProto -> {
359 String pathName = tsKvProto.getKv().getKey(); 361 String pathName = tsKvProto.getKv().getKey();
360 Object valueNew = this.lwM2mTransportContextServer.getValueFromKvProto(tsKvProto.getKv()); 362 Object valueNew = this.lwM2mTransportContextServer.getValueFromKvProto(tsKvProto.getKv());
361 - if (FIRMWARE_VERSION.equals(pathName) && !valueNew.equals(lwM2MClient.getFrUpdate().getCurrentFwVersion())) { 363 + if (FirmwareUtil.getAttributeKey(FirmwareType.FIRMWARE, FirmwareKey.VERSION).equals(pathName) && !valueNew.equals(lwM2MClient.getFrUpdate().getCurrentFwVersion())) {
362 lwM2MClient.getFrUpdate().setCurrentFwVersion((String) valueNew); 364 lwM2MClient.getFrUpdate().setCurrentFwVersion((String) valueNew);
363 } 365 }
364 }); 366 });
@@ -47,6 +47,7 @@ import org.thingsboard.server.common.data.DeviceProfile; @@ -47,6 +47,7 @@ import org.thingsboard.server.common.data.DeviceProfile;
47 import org.thingsboard.server.common.data.DeviceTransportType; 47 import org.thingsboard.server.common.data.DeviceTransportType;
48 import org.thingsboard.server.common.data.TransportPayloadType; 48 import org.thingsboard.server.common.data.TransportPayloadType;
49 import org.thingsboard.server.common.data.device.profile.MqttTopics; 49 import org.thingsboard.server.common.data.device.profile.MqttTopics;
  50 +import org.thingsboard.server.common.data.firmware.FirmwareType;
50 import org.thingsboard.server.common.data.id.FirmwareId; 51 import org.thingsboard.server.common.data.id.FirmwareId;
51 import org.thingsboard.server.common.msg.EncryptionUtil; 52 import org.thingsboard.server.common.msg.EncryptionUtil;
52 import org.thingsboard.server.common.msg.tools.TbRateLimitsException; 53 import org.thingsboard.server.common.msg.tools.TbRateLimitsException;
@@ -59,6 +60,7 @@ import org.thingsboard.server.common.transport.auth.TransportDeviceInfo; @@ -59,6 +60,7 @@ import org.thingsboard.server.common.transport.auth.TransportDeviceInfo;
59 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; 60 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
60 import org.thingsboard.server.common.transport.service.DefaultTransportService; 61 import org.thingsboard.server.common.transport.service.DefaultTransportService;
61 import org.thingsboard.server.common.transport.service.SessionMetaData; 62 import org.thingsboard.server.common.transport.service.SessionMetaData;
  63 +import org.thingsboard.server.common.transport.util.SslUtil;
62 import org.thingsboard.server.gen.transport.TransportProtos; 64 import org.thingsboard.server.gen.transport.TransportProtos;
63 import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsg; 65 import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsg;
64 import org.thingsboard.server.gen.transport.TransportProtos.SessionEvent; 66 import org.thingsboard.server.gen.transport.TransportProtos.SessionEvent;
@@ -68,7 +70,6 @@ import org.thingsboard.server.transport.mqtt.adaptors.MqttTransportAdaptor; @@ -68,7 +70,6 @@ import org.thingsboard.server.transport.mqtt.adaptors.MqttTransportAdaptor;
68 import org.thingsboard.server.transport.mqtt.session.DeviceSessionCtx; 70 import org.thingsboard.server.transport.mqtt.session.DeviceSessionCtx;
69 import org.thingsboard.server.transport.mqtt.session.GatewaySessionHandler; 71 import org.thingsboard.server.transport.mqtt.session.GatewaySessionHandler;
70 import org.thingsboard.server.transport.mqtt.session.MqttTopicMatcher; 72 import org.thingsboard.server.transport.mqtt.session.MqttTopicMatcher;
71 -import org.thingsboard.server.common.transport.util.SslUtil;  
72 73
73 import javax.net.ssl.SSLPeerUnverifiedException; 74 import javax.net.ssl.SSLPeerUnverifiedException;
74 import java.io.IOException; 75 import java.io.IOException;
@@ -97,6 +98,8 @@ import static io.netty.handler.codec.mqtt.MqttMessageType.UNSUBACK; @@ -97,6 +98,8 @@ import static io.netty.handler.codec.mqtt.MqttMessageType.UNSUBACK;
97 import static io.netty.handler.codec.mqtt.MqttQoS.AT_LEAST_ONCE; 98 import static io.netty.handler.codec.mqtt.MqttQoS.AT_LEAST_ONCE;
98 import static io.netty.handler.codec.mqtt.MqttQoS.AT_MOST_ONCE; 99 import static io.netty.handler.codec.mqtt.MqttQoS.AT_MOST_ONCE;
99 import static io.netty.handler.codec.mqtt.MqttQoS.FAILURE; 100 import static io.netty.handler.codec.mqtt.MqttQoS.FAILURE;
  101 +import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_FIRMWARE_REQUEST_TOPIC_PATTERN;
  102 +import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_SOFTWARE_REQUEST_TOPIC_PATTERN;
100 103
101 /** 104 /**
102 * @author Andrew Shvayka 105 * @author Andrew Shvayka
@@ -104,7 +107,9 @@ import static io.netty.handler.codec.mqtt.MqttQoS.FAILURE; @@ -104,7 +107,9 @@ import static io.netty.handler.codec.mqtt.MqttQoS.FAILURE;
104 @Slf4j 107 @Slf4j
105 public class MqttTransportHandler extends ChannelInboundHandlerAdapter implements GenericFutureListener<Future<? super Void>>, SessionMsgListener { 108 public class MqttTransportHandler extends ChannelInboundHandlerAdapter implements GenericFutureListener<Future<? super Void>>, SessionMsgListener {
106 109
107 - private static final Pattern FW_PATTERN = Pattern.compile("v2/fw/request/(?<requestId>\\d+)/chunk/(?<chunk>\\d+)"); 110 + private static final Pattern FW_REQUEST_PATTERN = Pattern.compile(DEVICE_FIRMWARE_REQUEST_TOPIC_PATTERN);
  111 + private static final Pattern SW_REQUEST_PATTERN = Pattern.compile(DEVICE_SOFTWARE_REQUEST_TOPIC_PATTERN);
  112 +
108 113
109 private static final String PAYLOAD_TOO_LARGE = "PAYLOAD_TOO_LARGE"; 114 private static final String PAYLOAD_TOO_LARGE = "PAYLOAD_TOO_LARGE";
110 115
@@ -314,38 +319,10 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement @@ -314,38 +319,10 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
314 } else if (topicName.equals(MqttTopics.DEVICE_CLAIM_TOPIC)) { 319 } else if (topicName.equals(MqttTopics.DEVICE_CLAIM_TOPIC)) {
315 TransportProtos.ClaimDeviceMsg claimDeviceMsg = payloadAdaptor.convertToClaimDevice(deviceSessionCtx, mqttMsg); 320 TransportProtos.ClaimDeviceMsg claimDeviceMsg = payloadAdaptor.convertToClaimDevice(deviceSessionCtx, mqttMsg);
316 transportService.process(deviceSessionCtx.getSessionInfo(), claimDeviceMsg, getPubAckCallback(ctx, msgId, claimDeviceMsg)); 321 transportService.process(deviceSessionCtx.getSessionInfo(), claimDeviceMsg, getPubAckCallback(ctx, msgId, claimDeviceMsg));
317 - } else if ((fwMatcher = FW_PATTERN.matcher(topicName)).find()) {  
318 - String payload = mqttMsg.content().toString(UTF8);  
319 - int chunkSize = StringUtils.isNotEmpty(payload) ? Integer.parseInt(payload) : 0;  
320 - String requestId = fwMatcher.group("requestId");  
321 - int chunk = Integer.parseInt(fwMatcher.group("chunk"));  
322 -  
323 - if (chunkSize > 0) {  
324 - this.fwChunkSizes.put(requestId, chunkSize);  
325 - } else {  
326 - chunkSize = fwChunkSizes.getOrDefault(requestId, 0);  
327 - }  
328 -  
329 - if (chunkSize > context.getMaxPayloadSize()) {  
330 - sendFirmwareError(ctx, PAYLOAD_TOO_LARGE);  
331 - return;  
332 - }  
333 -  
334 - String firmwareId = fwSessions.get(requestId);  
335 -  
336 - if (firmwareId != null) {  
337 - sendFirmware(ctx, mqttMsg.variableHeader().packetId(), firmwareId, requestId, chunkSize, chunk);  
338 - } else {  
339 - TransportProtos.SessionInfoProto sessionInfo = deviceSessionCtx.getSessionInfo();  
340 - TransportProtos.GetFirmwareRequestMsg getFirmwareRequestMsg = TransportProtos.GetFirmwareRequestMsg.newBuilder()  
341 - .setDeviceIdMSB(sessionInfo.getDeviceIdMSB())  
342 - .setDeviceIdLSB(sessionInfo.getDeviceIdLSB())  
343 - .setTenantIdMSB(sessionInfo.getTenantIdMSB())  
344 - .setTenantIdLSB(sessionInfo.getTenantIdLSB())  
345 - .build();  
346 - transportService.process(deviceSessionCtx.getSessionInfo(), getFirmwareRequestMsg,  
347 - new FirmwareCallback(ctx, mqttMsg.variableHeader().packetId(), getFirmwareRequestMsg, requestId, chunkSize, chunk));  
348 - } 322 + } else if ((fwMatcher = FW_REQUEST_PATTERN.matcher(topicName)).find()) {
  323 + getFirmwareCallback(ctx, mqttMsg, msgId, fwMatcher, FirmwareType.FIRMWARE);
  324 + } else if ((fwMatcher = SW_REQUEST_PATTERN.matcher(topicName)).find()) {
  325 + getFirmwareCallback(ctx, mqttMsg, msgId, fwMatcher, FirmwareType.SOFTWARE);
349 } else { 326 } else {
350 transportService.reportActivity(deviceSessionCtx.getSessionInfo()); 327 transportService.reportActivity(deviceSessionCtx.getSessionInfo());
351 ack(ctx, msgId); 328 ack(ctx, msgId);
@@ -357,6 +334,41 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement @@ -357,6 +334,41 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
357 } 334 }
358 } 335 }
359 336
  337 + private void getFirmwareCallback(ChannelHandlerContext ctx, MqttPublishMessage mqttMsg, int msgId, Matcher fwMatcher, FirmwareType type) {
  338 + String payload = mqttMsg.content().toString(UTF8);
  339 + int chunkSize = StringUtils.isNotEmpty(payload) ? Integer.parseInt(payload) : 0;
  340 + String requestId = fwMatcher.group("requestId");
  341 + int chunk = Integer.parseInt(fwMatcher.group("chunk"));
  342 +
  343 + if (chunkSize > 0) {
  344 + this.fwChunkSizes.put(requestId, chunkSize);
  345 + } else {
  346 + chunkSize = fwChunkSizes.getOrDefault(requestId, 0);
  347 + }
  348 +
  349 + if (chunkSize > context.getMaxPayloadSize()) {
  350 + sendFirmwareError(ctx, PAYLOAD_TOO_LARGE);
  351 + return;
  352 + }
  353 +
  354 + String firmwareId = fwSessions.get(requestId);
  355 +
  356 + if (firmwareId != null) {
  357 + sendFirmware(ctx, mqttMsg.variableHeader().packetId(), firmwareId, requestId, chunkSize, chunk, type);
  358 + } else {
  359 + TransportProtos.SessionInfoProto sessionInfo = deviceSessionCtx.getSessionInfo();
  360 + TransportProtos.GetFirmwareRequestMsg getFirmwareRequestMsg = TransportProtos.GetFirmwareRequestMsg.newBuilder()
  361 + .setDeviceIdMSB(sessionInfo.getDeviceIdMSB())
  362 + .setDeviceIdLSB(sessionInfo.getDeviceIdLSB())
  363 + .setTenantIdMSB(sessionInfo.getTenantIdMSB())
  364 + .setTenantIdLSB(sessionInfo.getTenantIdLSB())
  365 + .setType(type.name())
  366 + .build();
  367 + transportService.process(deviceSessionCtx.getSessionInfo(), getFirmwareRequestMsg,
  368 + new FirmwareCallback(ctx, msgId, getFirmwareRequestMsg, requestId, chunkSize, chunk));
  369 + }
  370 + }
  371 +
360 private void ack(ChannelHandlerContext ctx, int msgId) { 372 private void ack(ChannelHandlerContext ctx, int msgId) {
361 if (msgId > 0) { 373 if (msgId > 0) {
362 ctx.writeAndFlush(createMqttPubAckMsg(msgId)); 374 ctx.writeAndFlush(createMqttPubAckMsg(msgId));
@@ -435,7 +447,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement @@ -435,7 +447,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
435 if (TransportProtos.ResponseStatus.SUCCESS.equals(response.getResponseStatus())) { 447 if (TransportProtos.ResponseStatus.SUCCESS.equals(response.getResponseStatus())) {
436 FirmwareId firmwareId = new FirmwareId(new UUID(response.getFirmwareIdMSB(), response.getFirmwareIdLSB())); 448 FirmwareId firmwareId = new FirmwareId(new UUID(response.getFirmwareIdMSB(), response.getFirmwareIdLSB()));
437 fwSessions.put(requestId, firmwareId.toString()); 449 fwSessions.put(requestId, firmwareId.toString());
438 - sendFirmware(ctx, msgId, firmwareId.toString(), requestId, chunkSize, chunk); 450 + sendFirmware(ctx, msgId, firmwareId.toString(), requestId, chunkSize, chunk, FirmwareType.valueOf(response.getType()));
439 } else { 451 } else {
440 sendFirmwareError(ctx, response.getResponseStatus().toString()); 452 sendFirmwareError(ctx, response.getResponseStatus().toString());
441 } 453 }
@@ -448,13 +460,13 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement @@ -448,13 +460,13 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
448 } 460 }
449 } 461 }
450 462
451 - private void sendFirmware(ChannelHandlerContext ctx, int msgId, String firmwareId, String requestId, int chunkSize, int chunk) { 463 + private void sendFirmware(ChannelHandlerContext ctx, int msgId, String firmwareId, String requestId, int chunkSize, int chunk, FirmwareType type) {
452 log.trace("[{}] Send firmware [{}] to device!", sessionId, firmwareId); 464 log.trace("[{}] Send firmware [{}] to device!", sessionId, firmwareId);
453 ack(ctx, msgId); 465 ack(ctx, msgId);
454 try { 466 try {
455 byte[] firmwareChunk = context.getFirmwareDataCache().get(firmwareId, chunkSize, chunk); 467 byte[] firmwareChunk = context.getFirmwareDataCache().get(firmwareId, chunkSize, chunk);
456 deviceSessionCtx.getPayloadAdaptor() 468 deviceSessionCtx.getPayloadAdaptor()
457 - .convertToPublish(deviceSessionCtx, firmwareChunk, requestId, chunk) 469 + .convertToPublish(deviceSessionCtx, firmwareChunk, requestId, chunk, type)
458 .ifPresent(deviceSessionCtx.getChannel()::writeAndFlush); 470 .ifPresent(deviceSessionCtx.getChannel()::writeAndFlush);
459 if (firmwareChunk != null && chunkSize != firmwareChunk.length) { 471 if (firmwareChunk != null && chunkSize != firmwareChunk.length) {
460 scheduler.schedule(() -> processDisconnect(ctx), 60, TimeUnit.SECONDS); 472 scheduler.schedule(() -> processDisconnect(ctx), 60, TimeUnit.SECONDS);
@@ -504,6 +516,8 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement @@ -504,6 +516,8 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
504 case MqttTopics.DEVICE_PROVISION_RESPONSE_TOPIC: 516 case MqttTopics.DEVICE_PROVISION_RESPONSE_TOPIC:
505 case MqttTopics.DEVICE_FIRMWARE_RESPONSES_TOPIC: 517 case MqttTopics.DEVICE_FIRMWARE_RESPONSES_TOPIC:
506 case MqttTopics.DEVICE_FIRMWARE_ERROR_TOPIC: 518 case MqttTopics.DEVICE_FIRMWARE_ERROR_TOPIC:
  519 + case MqttTopics.DEVICE_SOFTWARE_RESPONSES_TOPIC:
  520 + case MqttTopics.DEVICE_SOFTWARE_ERROR_TOPIC:
507 registerSubQoS(topic, grantedQoSList, reqQoS); 521 registerSubQoS(topic, grantedQoSList, reqQoS);
508 break; 522 break;
509 default: 523 default:
@@ -30,6 +30,7 @@ import lombok.extern.slf4j.Slf4j; @@ -30,6 +30,7 @@ import lombok.extern.slf4j.Slf4j;
30 import org.springframework.stereotype.Component; 30 import org.springframework.stereotype.Component;
31 import org.springframework.util.StringUtils; 31 import org.springframework.util.StringUtils;
32 import org.thingsboard.server.common.data.device.profile.MqttTopics; 32 import org.thingsboard.server.common.data.device.profile.MqttTopics;
  33 +import org.thingsboard.server.common.data.firmware.FirmwareType;
33 import org.thingsboard.server.common.transport.adaptor.AdaptorException; 34 import org.thingsboard.server.common.transport.adaptor.AdaptorException;
34 import org.thingsboard.server.common.transport.adaptor.JsonConverter; 35 import org.thingsboard.server.common.transport.adaptor.JsonConverter;
35 import org.thingsboard.server.gen.transport.TransportProtos; 36 import org.thingsboard.server.gen.transport.TransportProtos;
@@ -43,6 +44,9 @@ import java.util.Optional; @@ -43,6 +44,9 @@ import java.util.Optional;
43 import java.util.Set; 44 import java.util.Set;
44 import java.util.UUID; 45 import java.util.UUID;
45 46
  47 +import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_FIRMWARE_RESPONSES_TOPIC_FORMAT;
  48 +
  49 +
46 /** 50 /**
47 * @author Andrew Shvayka 51 * @author Andrew Shvayka
48 */ 52 */
@@ -151,8 +155,8 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor { @@ -151,8 +155,8 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor {
151 } 155 }
152 156
153 @Override 157 @Override
154 - public Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk) {  
155 - return Optional.of(createMqttPublishMsg(ctx, MqttTopics.DEVICE_FIRMWARE_RESPONSE_TOPIC_PREFIX + requestId + "/chunk/" + chunk, firmwareChunk)); 158 + public Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk, FirmwareType firmwareType) {
  159 + return Optional.of(createMqttPublishMsg(ctx, String.format(DEVICE_FIRMWARE_RESPONSES_TOPIC_FORMAT, firmwareType.getKeyPrefix(), requestId, chunk), firmwareChunk));
156 } 160 }
157 161
158 public static JsonElement validateJsonPayload(UUID sessionId, ByteBuf payloadData) throws AdaptorException { 162 public static JsonElement validateJsonPayload(UUID sessionId, ByteBuf payloadData) throws AdaptorException {
@@ -23,6 +23,7 @@ import io.netty.handler.codec.mqtt.MqttMessage; @@ -23,6 +23,7 @@ import io.netty.handler.codec.mqtt.MqttMessage;
23 import io.netty.handler.codec.mqtt.MqttMessageType; 23 import io.netty.handler.codec.mqtt.MqttMessageType;
24 import io.netty.handler.codec.mqtt.MqttPublishMessage; 24 import io.netty.handler.codec.mqtt.MqttPublishMessage;
25 import io.netty.handler.codec.mqtt.MqttPublishVariableHeader; 25 import io.netty.handler.codec.mqtt.MqttPublishVariableHeader;
  26 +import org.thingsboard.server.common.data.firmware.FirmwareType;
26 import org.thingsboard.server.common.transport.adaptor.AdaptorException; 27 import org.thingsboard.server.common.transport.adaptor.AdaptorException;
27 import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; 28 import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg;
28 import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg; 29 import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg;
@@ -77,7 +78,7 @@ public interface MqttTransportAdaptor { @@ -77,7 +78,7 @@ public interface MqttTransportAdaptor {
77 78
78 Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, ProvisionDeviceResponseMsg provisionResponse) throws AdaptorException; 79 Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, ProvisionDeviceResponseMsg provisionResponse) throws AdaptorException;
79 80
80 - Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk) throws AdaptorException; 81 + Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk, FirmwareType firmwareType) throws AdaptorException;
81 82
82 default MqttPublishMessage createMqttPublishMsg(MqttDeviceAwareSessionContext ctx, String topic, byte[] payloadInBytes) { 83 default MqttPublishMessage createMqttPublishMsg(MqttDeviceAwareSessionContext ctx, String topic, byte[] payloadInBytes) {
83 MqttFixedHeader mqttFixedHeader = 84 MqttFixedHeader mqttFixedHeader =
@@ -28,6 +28,7 @@ import lombok.extern.slf4j.Slf4j; @@ -28,6 +28,7 @@ import lombok.extern.slf4j.Slf4j;
28 import org.springframework.stereotype.Component; 28 import org.springframework.stereotype.Component;
29 import org.springframework.util.StringUtils; 29 import org.springframework.util.StringUtils;
30 import org.thingsboard.server.common.data.device.profile.MqttTopics; 30 import org.thingsboard.server.common.data.device.profile.MqttTopics;
  31 +import org.thingsboard.server.common.data.firmware.FirmwareType;
31 import org.thingsboard.server.common.transport.adaptor.AdaptorException; 32 import org.thingsboard.server.common.transport.adaptor.AdaptorException;
32 import org.thingsboard.server.common.transport.adaptor.JsonConverter; 33 import org.thingsboard.server.common.transport.adaptor.JsonConverter;
33 import org.thingsboard.server.common.transport.adaptor.ProtoConverter; 34 import org.thingsboard.server.common.transport.adaptor.ProtoConverter;
@@ -38,6 +39,8 @@ import org.thingsboard.server.transport.mqtt.session.MqttDeviceAwareSessionConte @@ -38,6 +39,8 @@ import org.thingsboard.server.transport.mqtt.session.MqttDeviceAwareSessionConte
38 39
39 import java.util.Optional; 40 import java.util.Optional;
40 41
  42 +import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_FIRMWARE_RESPONSES_TOPIC_FORMAT;
  43 +
41 @Component 44 @Component
42 @Slf4j 45 @Slf4j
43 public class ProtoMqttAdaptor implements MqttTransportAdaptor { 46 public class ProtoMqttAdaptor implements MqttTransportAdaptor {
@@ -165,8 +168,8 @@ public class ProtoMqttAdaptor implements MqttTransportAdaptor { @@ -165,8 +168,8 @@ public class ProtoMqttAdaptor implements MqttTransportAdaptor {
165 } 168 }
166 169
167 @Override 170 @Override
168 - public Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk) throws AdaptorException {  
169 - return Optional.of(createMqttPublishMsg(ctx, MqttTopics.DEVICE_FIRMWARE_RESPONSE_TOPIC_PREFIX + requestId + "/" + chunk, firmwareChunk)); 171 + public Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk, FirmwareType firmwareType) throws AdaptorException {
  172 + return Optional.of(createMqttPublishMsg(ctx, String.format(DEVICE_FIRMWARE_RESPONSES_TOPIC_FORMAT, firmwareType.getKeyPrefix(), requestId, chunk), firmwareChunk));
170 } 173 }
171 174
172 @Override 175 @Override
@@ -83,6 +83,8 @@ public interface DeviceDao extends Dao<Device>, TenantEntityDao { @@ -83,6 +83,8 @@ public interface DeviceDao extends Dao<Device>, TenantEntityDao {
83 83
84 PageData<Device> findDevicesByTenantIdAndTypeAndEmptyFirmware(UUID tenantId, String type, PageLink pageLink); 84 PageData<Device> findDevicesByTenantIdAndTypeAndEmptyFirmware(UUID tenantId, String type, PageLink pageLink);
85 85
  86 + PageData<Device> findDevicesByTenantIdAndTypeAndEmptySoftware(UUID tenantId, String type, PageLink pageLink);
  87 +
86 /** 88 /**
87 * Find device infos by tenantId, type and page link. 89 * Find device infos by tenantId, type and page link.
88 * 90 *
@@ -56,6 +56,7 @@ import org.thingsboard.server.common.data.device.profile.DisabledDeviceProfilePr @@ -56,6 +56,7 @@ import org.thingsboard.server.common.data.device.profile.DisabledDeviceProfilePr
56 import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; 56 import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;
57 import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration; 57 import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
58 import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; 58 import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
  59 +import org.thingsboard.server.common.data.firmware.FirmwareType;
59 import org.thingsboard.server.common.data.id.DeviceProfileId; 60 import org.thingsboard.server.common.data.id.DeviceProfileId;
60 import org.thingsboard.server.common.data.id.TenantId; 61 import org.thingsboard.server.common.data.id.TenantId;
61 import org.thingsboard.server.common.data.page.PageData; 62 import org.thingsboard.server.common.data.page.PageData;
@@ -406,9 +407,31 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @@ -406,9 +407,31 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
406 if (firmware == null) { 407 if (firmware == null) {
407 throw new DataValidationException("Can't assign non-existent firmware!"); 408 throw new DataValidationException("Can't assign non-existent firmware!");
408 } 409 }
  410 + if (!firmware.getType().equals(FirmwareType.FIRMWARE)) {
  411 + throw new DataValidationException("Can't assign firmware with type: " + firmware.getType());
  412 + }
409 if (firmware.getData() == null) { 413 if (firmware.getData() == null) {
410 throw new DataValidationException("Can't assign firmware with empty data!"); 414 throw new DataValidationException("Can't assign firmware with empty data!");
411 } 415 }
  416 + if (!firmware.getDeviceProfileId().equals(deviceProfile.getId())) {
  417 + throw new DataValidationException("Can't assign firmware with different deviceProfile!");
  418 + }
  419 + }
  420 +
  421 + if (deviceProfile.getSoftwareId() != null) {
  422 + Firmware software = firmwareService.findFirmwareById(tenantId, deviceProfile.getSoftwareId());
  423 + if (software == null) {
  424 + throw new DataValidationException("Can't assign non-existent software!");
  425 + }
  426 + if (!software.getType().equals(FirmwareType.SOFTWARE)) {
  427 + throw new DataValidationException("Can't assign software with type: " + software.getType());
  428 + }
  429 + if (software.getData() == null) {
  430 + throw new DataValidationException("Can't assign software with empty data!");
  431 + }
  432 + if (!software.getDeviceProfileId().equals(deviceProfile.getId())) {
  433 + throw new DataValidationException("Can't assign firmware with different deviceProfile!");
  434 + }
412 } 435 }
413 } 436 }
414 437
@@ -53,6 +53,7 @@ import org.thingsboard.server.common.data.device.data.Lwm2mDeviceTransportConfig @@ -53,6 +53,7 @@ import org.thingsboard.server.common.data.device.data.Lwm2mDeviceTransportConfig
53 import org.thingsboard.server.common.data.device.data.MqttDeviceTransportConfiguration; 53 import org.thingsboard.server.common.data.device.data.MqttDeviceTransportConfiguration;
54 import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration; 54 import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration;
55 import org.thingsboard.server.common.data.edge.Edge; 55 import org.thingsboard.server.common.data.edge.Edge;
  56 +import org.thingsboard.server.common.data.firmware.FirmwareType;
56 import org.thingsboard.server.common.data.id.CustomerId; 57 import org.thingsboard.server.common.data.id.CustomerId;
57 import org.thingsboard.server.common.data.id.DeviceId; 58 import org.thingsboard.server.common.data.id.DeviceId;
58 import org.thingsboard.server.common.data.id.DeviceProfileId; 59 import org.thingsboard.server.common.data.id.DeviceProfileId;
@@ -361,7 +362,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe @@ -361,7 +362,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
361 362
362 @Override 363 @Override
363 public PageData<Device> findDevicesByTenantIdAndTypeAndEmptyFirmware(TenantId tenantId, String type, PageLink pageLink) { 364 public PageData<Device> findDevicesByTenantIdAndTypeAndEmptyFirmware(TenantId tenantId, String type, PageLink pageLink) {
364 - log.trace("Executing findDevicesByTenantIdAndType, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink); 365 + log.trace("Executing findDevicesByTenantIdAndTypeAndEmptyFirmware, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink);
365 validateId(tenantId, INCORRECT_TENANT_ID + tenantId); 366 validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
366 validateString(type, "Incorrect type " + type); 367 validateString(type, "Incorrect type " + type);
367 validatePageLink(pageLink); 368 validatePageLink(pageLink);
@@ -369,6 +370,15 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe @@ -369,6 +370,15 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
369 } 370 }
370 371
371 @Override 372 @Override
  373 + public PageData<Device> findDevicesByTenantIdAndTypeAndEmptySoftware(TenantId tenantId, String type, PageLink pageLink) {
  374 + log.trace("Executing findDevicesByTenantIdAndTypeAndEmptySoftware, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink);
  375 + validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
  376 + validateString(type, "Incorrect type " + type);
  377 + validatePageLink(pageLink);
  378 + return deviceDao.findDevicesByTenantIdAndTypeAndEmptySoftware(tenantId.getId(), type, pageLink);
  379 + }
  380 +
  381 + @Override
372 public PageData<DeviceInfo> findDeviceInfosByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink) { 382 public PageData<DeviceInfo> findDeviceInfosByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink) {
373 log.trace("Executing findDeviceInfosByTenantIdAndType, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink); 383 log.trace("Executing findDeviceInfosByTenantIdAndType, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink);
374 validateId(tenantId, INCORRECT_TENANT_ID + tenantId); 384 validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
@@ -696,9 +706,31 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe @@ -696,9 +706,31 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
696 if (firmware == null) { 706 if (firmware == null) {
697 throw new DataValidationException("Can't assign non-existent firmware!"); 707 throw new DataValidationException("Can't assign non-existent firmware!");
698 } 708 }
  709 + if (!firmware.getType().equals(FirmwareType.FIRMWARE)) {
  710 + throw new DataValidationException("Can't assign firmware with type: " + firmware.getType());
  711 + }
699 if (firmware.getData() == null) { 712 if (firmware.getData() == null) {
700 throw new DataValidationException("Can't assign firmware with empty data!"); 713 throw new DataValidationException("Can't assign firmware with empty data!");
701 } 714 }
  715 + if (!firmware.getDeviceProfileId().equals(device.getDeviceProfileId())) {
  716 + throw new DataValidationException("Can't assign firmware with different deviceProfile!");
  717 + }
  718 + }
  719 +
  720 + if (device.getSoftwareId() != null) {
  721 + Firmware software = firmwareService.findFirmwareById(tenantId, device.getSoftwareId());
  722 + if (software == null) {
  723 + throw new DataValidationException("Can't assign non-existent software!");
  724 + }
  725 + if (!software.getType().equals(FirmwareType.SOFTWARE)) {
  726 + throw new DataValidationException("Can't assign software with type: " + software.getType());
  727 + }
  728 + if (software.getData() == null) {
  729 + throw new DataValidationException("Can't assign software with empty data!");
  730 + }
  731 + if (!software.getDeviceProfileId().equals(device.getDeviceProfileId())) {
  732 + throw new DataValidationException("Can't assign firmware with different deviceProfile!");
  733 + }
702 } 734 }
703 } 735 }
704 }; 736 };
@@ -27,13 +27,17 @@ import org.springframework.cache.CacheManager; @@ -27,13 +27,17 @@ import org.springframework.cache.CacheManager;
27 import org.springframework.cache.annotation.Cacheable; 27 import org.springframework.cache.annotation.Cacheable;
28 import org.springframework.stereotype.Service; 28 import org.springframework.stereotype.Service;
29 import org.thingsboard.server.cache.firmware.FirmwareDataCache; 29 import org.thingsboard.server.cache.firmware.FirmwareDataCache;
  30 +import org.thingsboard.server.common.data.DeviceProfile;
30 import org.thingsboard.server.common.data.Firmware; 31 import org.thingsboard.server.common.data.Firmware;
31 import org.thingsboard.server.common.data.FirmwareInfo; 32 import org.thingsboard.server.common.data.FirmwareInfo;
32 import org.thingsboard.server.common.data.Tenant; 33 import org.thingsboard.server.common.data.Tenant;
  34 +import org.thingsboard.server.common.data.firmware.FirmwareType;
  35 +import org.thingsboard.server.common.data.id.DeviceProfileId;
33 import org.thingsboard.server.common.data.id.FirmwareId; 36 import org.thingsboard.server.common.data.id.FirmwareId;
34 import org.thingsboard.server.common.data.id.TenantId; 37 import org.thingsboard.server.common.data.id.TenantId;
35 import org.thingsboard.server.common.data.page.PageData; 38 import org.thingsboard.server.common.data.page.PageData;
36 import org.thingsboard.server.common.data.page.PageLink; 39 import org.thingsboard.server.common.data.page.PageLink;
  40 +import org.thingsboard.server.dao.device.DeviceProfileDao;
37 import org.thingsboard.server.dao.exception.DataValidationException; 41 import org.thingsboard.server.dao.exception.DataValidationException;
38 import org.thingsboard.server.dao.service.DataValidator; 42 import org.thingsboard.server.dao.service.DataValidator;
39 import org.thingsboard.server.dao.service.PaginatedRemover; 43 import org.thingsboard.server.dao.service.PaginatedRemover;
@@ -56,6 +60,7 @@ public class BaseFirmwareService implements FirmwareService { @@ -56,6 +60,7 @@ public class BaseFirmwareService implements FirmwareService {
56 public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; 60 public static final String INCORRECT_TENANT_ID = "Incorrect tenantId ";
57 61
58 private final TenantDao tenantDao; 62 private final TenantDao tenantDao;
  63 + private final DeviceProfileDao deviceProfileDao;
59 private final FirmwareDao firmwareDao; 64 private final FirmwareDao firmwareDao;
60 private final FirmwareInfoDao firmwareInfoDao; 65 private final FirmwareInfoDao firmwareInfoDao;
61 private final CacheManager cacheManager; 66 private final CacheManager cacheManager;
@@ -124,7 +129,8 @@ public class BaseFirmwareService implements FirmwareService { @@ -124,7 +129,8 @@ public class BaseFirmwareService implements FirmwareService {
124 public ListenableFuture<FirmwareInfo> findFirmwareInfoByIdAsync(TenantId tenantId, FirmwareId firmwareId) { 129 public ListenableFuture<FirmwareInfo> findFirmwareInfoByIdAsync(TenantId tenantId, FirmwareId firmwareId) {
125 log.trace("Executing findFirmwareInfoByIdAsync [{}]", firmwareId); 130 log.trace("Executing findFirmwareInfoByIdAsync [{}]", firmwareId);
126 validateId(firmwareId, INCORRECT_FIRMWARE_ID + firmwareId); 131 validateId(firmwareId, INCORRECT_FIRMWARE_ID + firmwareId);
127 - return firmwareInfoDao.findByIdAsync(tenantId, firmwareId.getId()); } 132 + return firmwareInfoDao.findByIdAsync(tenantId, firmwareId.getId());
  133 + }
128 134
129 @Override 135 @Override
130 public PageData<FirmwareInfo> findTenantFirmwaresByTenantId(TenantId tenantId, PageLink pageLink) { 136 public PageData<FirmwareInfo> findTenantFirmwaresByTenantId(TenantId tenantId, PageLink pageLink) {
@@ -135,11 +141,11 @@ public class BaseFirmwareService implements FirmwareService { @@ -135,11 +141,11 @@ public class BaseFirmwareService implements FirmwareService {
135 } 141 }
136 142
137 @Override 143 @Override
138 - public PageData<FirmwareInfo> findTenantFirmwaresByTenantIdAndHasData(TenantId tenantId, boolean hasData, PageLink pageLink) { 144 + public PageData<FirmwareInfo> findTenantFirmwaresByTenantIdAndDeviceProfileIdAndTypeAndHasData(TenantId tenantId, DeviceProfileId deviceProfileId, FirmwareType firmwareType, boolean hasData, PageLink pageLink) {
139 log.trace("Executing findTenantFirmwaresByTenantIdAndHasData, tenantId [{}], hasData [{}] pageLink [{}]", tenantId, hasData, pageLink); 145 log.trace("Executing findTenantFirmwaresByTenantIdAndHasData, tenantId [{}], hasData [{}] pageLink [{}]", tenantId, hasData, pageLink);
140 validateId(tenantId, INCORRECT_TENANT_ID + tenantId); 146 validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
141 validatePageLink(pageLink); 147 validatePageLink(pageLink);
142 - return firmwareInfoDao.findFirmwareInfoByTenantIdAndHasData(tenantId, hasData, pageLink); 148 + return firmwareInfoDao.findFirmwareInfoByTenantIdAndDeviceProfileIdAndTypeAndHasData(tenantId, deviceProfileId, firmwareType, hasData, pageLink);
143 } 149 }
144 150
145 @Override 151 @Override
@@ -157,6 +163,10 @@ public class BaseFirmwareService implements FirmwareService { @@ -157,6 +163,10 @@ public class BaseFirmwareService implements FirmwareService {
157 throw new DataValidationException("The firmware referenced by the devices cannot be deleted!"); 163 throw new DataValidationException("The firmware referenced by the devices cannot be deleted!");
158 } else if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("fk_firmware_device_profile")) { 164 } else if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("fk_firmware_device_profile")) {
159 throw new DataValidationException("The firmware referenced by the device profile cannot be deleted!"); 165 throw new DataValidationException("The firmware referenced by the device profile cannot be deleted!");
  166 + } else if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("fk_software_device")) {
  167 + throw new DataValidationException("The software referenced by the devices cannot be deleted!");
  168 + } else if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("fk_software_device_profile")) {
  169 + throw new DataValidationException("The software referenced by the device profile cannot be deleted!");
160 } else { 170 } else {
161 throw t; 171 throw t;
162 } 172 }
@@ -173,29 +183,15 @@ public class BaseFirmwareService implements FirmwareService { @@ -173,29 +183,15 @@ public class BaseFirmwareService implements FirmwareService {
173 private DataValidator<FirmwareInfo> firmwareInfoValidator = new DataValidator<>() { 183 private DataValidator<FirmwareInfo> firmwareInfoValidator = new DataValidator<>() {
174 184
175 @Override 185 @Override
176 - protected void validateDataImpl(TenantId tenantId, FirmwareInfo firmware) {  
177 - if (firmware.getTenantId() == null) {  
178 - throw new DataValidationException("Firmware should be assigned to tenant!");  
179 - } else {  
180 - Tenant tenant = tenantDao.findById(firmware.getTenantId(), firmware.getTenantId().getId());  
181 - if (tenant == null) {  
182 - throw new DataValidationException("Firmware is referencing to non-existent tenant!");  
183 - }  
184 - }  
185 -  
186 - if (StringUtils.isEmpty(firmware.getTitle())) {  
187 - throw new DataValidationException("Firmware title should be specified!");  
188 - }  
189 -  
190 - if (StringUtils.isEmpty(firmware.getVersion())) {  
191 - throw new DataValidationException("Firmware version should be specified!");  
192 - } 186 + protected void validateDataImpl(TenantId tenantId, FirmwareInfo firmwareInfo) {
  187 + validateImpl(firmwareInfo);
193 } 188 }
194 189
195 @Override 190 @Override
196 protected void validateUpdate(TenantId tenantId, FirmwareInfo firmware) { 191 protected void validateUpdate(TenantId tenantId, FirmwareInfo firmware) {
197 FirmwareInfo firmwareOld = firmwareInfoDao.findById(tenantId, firmware.getUuidId()); 192 FirmwareInfo firmwareOld = firmwareInfoDao.findById(tenantId, firmware.getUuidId());
198 193
  194 + validateUpdateDeviceProfile(firmware, firmwareOld);
199 BaseFirmwareService.validateUpdate(firmware, firmwareOld); 195 BaseFirmwareService.validateUpdate(firmware, firmwareOld);
200 } 196 }
201 }; 197 };
@@ -204,22 +200,7 @@ public class BaseFirmwareService implements FirmwareService { @@ -204,22 +200,7 @@ public class BaseFirmwareService implements FirmwareService {
204 200
205 @Override 201 @Override
206 protected void validateDataImpl(TenantId tenantId, Firmware firmware) { 202 protected void validateDataImpl(TenantId tenantId, Firmware firmware) {
207 - if (firmware.getTenantId() == null) {  
208 - throw new DataValidationException("Firmware should be assigned to tenant!");  
209 - } else {  
210 - Tenant tenant = tenantDao.findById(firmware.getTenantId(), firmware.getTenantId().getId());  
211 - if (tenant == null) {  
212 - throw new DataValidationException("Firmware is referencing to non-existent tenant!");  
213 - }  
214 - }  
215 -  
216 - if (StringUtils.isEmpty(firmware.getTitle())) {  
217 - throw new DataValidationException("Firmware title should be specified!");  
218 - }  
219 -  
220 - if (StringUtils.isEmpty(firmware.getVersion())) {  
221 - throw new DataValidationException("Firmware version should be specified!");  
222 - } 203 + validateImpl(firmware);
223 204
224 if (StringUtils.isEmpty(firmware.getFileName())) { 205 if (StringUtils.isEmpty(firmware.getFileName())) {
225 throw new DataValidationException("Firmware file name should be specified!"); 206 throw new DataValidationException("Firmware file name should be specified!");
@@ -267,6 +248,7 @@ public class BaseFirmwareService implements FirmwareService { @@ -267,6 +248,7 @@ public class BaseFirmwareService implements FirmwareService {
267 protected void validateUpdate(TenantId tenantId, Firmware firmware) { 248 protected void validateUpdate(TenantId tenantId, Firmware firmware) {
268 Firmware firmwareOld = firmwareDao.findById(tenantId, firmware.getUuidId()); 249 Firmware firmwareOld = firmwareDao.findById(tenantId, firmware.getUuidId());
269 250
  251 + validateUpdateDeviceProfile(firmware, firmwareOld);
270 BaseFirmwareService.validateUpdate(firmware, firmwareOld); 252 BaseFirmwareService.validateUpdate(firmware, firmwareOld);
271 253
272 if (firmwareOld.getData() != null && !firmwareOld.getData().equals(firmware.getData())) { 254 if (firmwareOld.getData() != null && !firmwareOld.getData().equals(firmware.getData())) {
@@ -275,7 +257,19 @@ public class BaseFirmwareService implements FirmwareService { @@ -275,7 +257,19 @@ public class BaseFirmwareService implements FirmwareService {
275 } 257 }
276 }; 258 };
277 259
  260 + private void validateUpdateDeviceProfile(FirmwareInfo firmware, FirmwareInfo firmwareOld) {
  261 + if (firmwareOld.getDeviceProfileId() != null && !firmwareOld.getDeviceProfileId().equals(firmware.getDeviceProfileId())) {
  262 + if (firmwareInfoDao.isFirmwareUsed(firmwareOld.getId(), firmware.getType(), firmwareOld.getDeviceProfileId())) {
  263 + throw new DataValidationException("Can`t update deviceProfileId because firmware is already in use!");
  264 + }
  265 + }
  266 + }
  267 +
278 private static void validateUpdate(FirmwareInfo firmware, FirmwareInfo firmwareOld) { 268 private static void validateUpdate(FirmwareInfo firmware, FirmwareInfo firmwareOld) {
  269 + if (!firmwareOld.getType().equals(firmware.getType())) {
  270 + throw new DataValidationException("Updating type is prohibited!");
  271 + }
  272 +
279 if (!firmwareOld.getTitle().equals(firmware.getTitle())) { 273 if (!firmwareOld.getTitle().equals(firmware.getTitle())) {
280 throw new DataValidationException("Updating firmware title is prohibited!"); 274 throw new DataValidationException("Updating firmware title is prohibited!");
281 } 275 }
@@ -305,6 +299,36 @@ public class BaseFirmwareService implements FirmwareService { @@ -305,6 +299,36 @@ public class BaseFirmwareService implements FirmwareService {
305 } 299 }
306 } 300 }
307 301
  302 + private void validateImpl(FirmwareInfo firmwareInfo) {
  303 + if (firmwareInfo.getTenantId() == null) {
  304 + throw new DataValidationException("Firmware should be assigned to tenant!");
  305 + } else {
  306 + Tenant tenant = tenantDao.findById(firmwareInfo.getTenantId(), firmwareInfo.getTenantId().getId());
  307 + if (tenant == null) {
  308 + throw new DataValidationException("Firmware is referencing to non-existent tenant!");
  309 + }
  310 + }
  311 +
  312 + if (firmwareInfo.getDeviceProfileId() != null) {
  313 + DeviceProfile deviceProfile = deviceProfileDao.findById(firmwareInfo.getTenantId(), firmwareInfo.getDeviceProfileId().getId());
  314 + if (deviceProfile == null) {
  315 + throw new DataValidationException("Firmware is referencing to non-existent device profile!");
  316 + }
  317 + }
  318 +
  319 + if (firmwareInfo.getType() == null) {
  320 + throw new DataValidationException("Type should be specified!");
  321 + }
  322 +
  323 + if (StringUtils.isEmpty(firmwareInfo.getTitle())) {
  324 + throw new DataValidationException("Firmware title should be specified!");
  325 + }
  326 +
  327 + if (StringUtils.isEmpty(firmwareInfo.getVersion())) {
  328 + throw new DataValidationException("Firmware version should be specified!");
  329 + }
  330 + }
  331 +
308 private PaginatedRemover<TenantId, FirmwareInfo> tenantFirmwareRemover = 332 private PaginatedRemover<TenantId, FirmwareInfo> tenantFirmwareRemover =
309 new PaginatedRemover<>() { 333 new PaginatedRemover<>() {
310 334
@@ -16,6 +16,9 @@ @@ -16,6 +16,9 @@
16 package org.thingsboard.server.dao.firmware; 16 package org.thingsboard.server.dao.firmware;
17 17
18 import org.thingsboard.server.common.data.FirmwareInfo; 18 import org.thingsboard.server.common.data.FirmwareInfo;
  19 +import org.thingsboard.server.common.data.firmware.FirmwareType;
  20 +import org.thingsboard.server.common.data.id.DeviceProfileId;
  21 +import org.thingsboard.server.common.data.id.FirmwareId;
19 import org.thingsboard.server.common.data.id.TenantId; 22 import org.thingsboard.server.common.data.id.TenantId;
20 import org.thingsboard.server.common.data.page.PageData; 23 import org.thingsboard.server.common.data.page.PageData;
21 import org.thingsboard.server.common.data.page.PageLink; 24 import org.thingsboard.server.common.data.page.PageLink;
@@ -27,6 +30,8 @@ public interface FirmwareInfoDao extends Dao<FirmwareInfo> { @@ -27,6 +30,8 @@ public interface FirmwareInfoDao extends Dao<FirmwareInfo> {
27 30
28 PageData<FirmwareInfo> findFirmwareInfoByTenantId(TenantId tenantId, PageLink pageLink); 31 PageData<FirmwareInfo> findFirmwareInfoByTenantId(TenantId tenantId, PageLink pageLink);
29 32
30 - PageData<FirmwareInfo> findFirmwareInfoByTenantIdAndHasData(TenantId tenantId, boolean hasData, PageLink pageLink); 33 + PageData<FirmwareInfo> findFirmwareInfoByTenantIdAndDeviceProfileIdAndTypeAndHasData(TenantId tenantId, DeviceProfileId deviceProfileId, FirmwareType firmwareType, boolean hasData, PageLink pageLink);
  34 +
  35 + boolean isFirmwareUsed(FirmwareId firmwareId, FirmwareType type, DeviceProfileId deviceProfileId);
31 36
32 } 37 }
@@ -154,6 +154,7 @@ public class ModelConstants { @@ -154,6 +154,7 @@ public class ModelConstants {
154 public static final String DEVICE_DEVICE_PROFILE_ID_PROPERTY = "device_profile_id"; 154 public static final String DEVICE_DEVICE_PROFILE_ID_PROPERTY = "device_profile_id";
155 public static final String DEVICE_DEVICE_DATA_PROPERTY = "device_data"; 155 public static final String DEVICE_DEVICE_DATA_PROPERTY = "device_data";
156 public static final String DEVICE_FIRMWARE_ID_PROPERTY = "firmware_id"; 156 public static final String DEVICE_FIRMWARE_ID_PROPERTY = "firmware_id";
  157 + public static final String DEVICE_SOFTWARE_ID_PROPERTY = "software_id";
157 158
158 public static final String DEVICE_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_and_search_text"; 159 public static final String DEVICE_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_and_search_text";
159 public static final String DEVICE_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_by_type_and_search_text"; 160 public static final String DEVICE_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_by_type_and_search_text";
@@ -178,6 +179,7 @@ public class ModelConstants { @@ -178,6 +179,7 @@ public class ModelConstants {
178 public static final String DEVICE_PROFILE_DEFAULT_QUEUE_NAME_PROPERTY = "default_queue_name"; 179 public static final String DEVICE_PROFILE_DEFAULT_QUEUE_NAME_PROPERTY = "default_queue_name";
179 public static final String DEVICE_PROFILE_PROVISION_DEVICE_KEY = "provision_device_key"; 180 public static final String DEVICE_PROFILE_PROVISION_DEVICE_KEY = "provision_device_key";
180 public static final String DEVICE_PROFILE_FIRMWARE_ID_PROPERTY = "firmware_id"; 181 public static final String DEVICE_PROFILE_FIRMWARE_ID_PROPERTY = "firmware_id";
  182 + public static final String DEVICE_PROFILE_SOFTWARE_ID_PROPERTY = "software_id";
181 183
182 /** 184 /**
183 * Cassandra entityView constants. 185 * Cassandra entityView constants.
@@ -476,6 +478,8 @@ public class ModelConstants { @@ -476,6 +478,8 @@ public class ModelConstants {
476 */ 478 */
477 public static final String FIRMWARE_TABLE_NAME = "firmware"; 479 public static final String FIRMWARE_TABLE_NAME = "firmware";
478 public static final String FIRMWARE_TENANT_ID_COLUMN = TENANT_ID_COLUMN; 480 public static final String FIRMWARE_TENANT_ID_COLUMN = TENANT_ID_COLUMN;
  481 + public static final String FIRMWARE_DEVICE_PROFILE_ID_COLUMN = "device_profile_id";
  482 + public static final String FIRMWARE_TYPE_COLUMN = "type";
479 public static final String FIRMWARE_TITLE_COLUMN = TITLE_PROPERTY; 483 public static final String FIRMWARE_TITLE_COLUMN = TITLE_PROPERTY;
480 public static final String FIRMWARE_VERSION_COLUMN = "version"; 484 public static final String FIRMWARE_VERSION_COLUMN = "version";
481 public static final String FIRMWARE_FILE_NAME_COLUMN = "file_name"; 485 public static final String FIRMWARE_FILE_NAME_COLUMN = "file_name";
@@ -22,6 +22,7 @@ import lombok.EqualsAndHashCode; @@ -22,6 +22,7 @@ import lombok.EqualsAndHashCode;
22 import org.hibernate.annotations.Type; 22 import org.hibernate.annotations.Type;
23 import org.hibernate.annotations.TypeDef; 23 import org.hibernate.annotations.TypeDef;
24 import org.hibernate.annotations.TypeDefs; 24 import org.hibernate.annotations.TypeDefs;
  25 +import org.thingsboard.common.util.JacksonUtil;
25 import org.thingsboard.server.common.data.Device; 26 import org.thingsboard.server.common.data.Device;
26 import org.thingsboard.server.common.data.device.data.DeviceData; 27 import org.thingsboard.server.common.data.device.data.DeviceData;
27 import org.thingsboard.server.common.data.id.CustomerId; 28 import org.thingsboard.server.common.data.id.CustomerId;
@@ -32,7 +33,6 @@ import org.thingsboard.server.common.data.id.TenantId; @@ -32,7 +33,6 @@ import org.thingsboard.server.common.data.id.TenantId;
32 import org.thingsboard.server.dao.model.BaseSqlEntity; 33 import org.thingsboard.server.dao.model.BaseSqlEntity;
33 import org.thingsboard.server.dao.model.ModelConstants; 34 import org.thingsboard.server.dao.model.ModelConstants;
34 import org.thingsboard.server.dao.model.SearchTextEntity; 35 import org.thingsboard.server.dao.model.SearchTextEntity;
35 -import org.thingsboard.common.util.JacksonUtil;  
36 import org.thingsboard.server.dao.util.mapping.JsonBinaryType; 36 import org.thingsboard.server.dao.util.mapping.JsonBinaryType;
37 import org.thingsboard.server.dao.util.mapping.JsonStringType; 37 import org.thingsboard.server.dao.util.mapping.JsonStringType;
38 38
@@ -43,8 +43,8 @@ import java.util.UUID; @@ -43,8 +43,8 @@ import java.util.UUID;
43 @Data 43 @Data
44 @EqualsAndHashCode(callSuper = true) 44 @EqualsAndHashCode(callSuper = true)
45 @TypeDefs({ 45 @TypeDefs({
46 - @TypeDef(name = "json", typeClass = JsonStringType.class),  
47 - @TypeDef(name = "jsonb", typeClass = JsonBinaryType.class) 46 + @TypeDef(name = "json", typeClass = JsonStringType.class),
  47 + @TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
48 }) 48 })
49 @MappedSuperclass 49 @MappedSuperclass
50 public abstract class AbstractDeviceEntity<T extends Device> extends BaseSqlEntity<T> implements SearchTextEntity<T> { 50 public abstract class AbstractDeviceEntity<T extends Device> extends BaseSqlEntity<T> implements SearchTextEntity<T> {
@@ -77,6 +77,9 @@ public abstract class AbstractDeviceEntity<T extends Device> extends BaseSqlEnti @@ -77,6 +77,9 @@ public abstract class AbstractDeviceEntity<T extends Device> extends BaseSqlEnti
77 @Column(name = ModelConstants.DEVICE_FIRMWARE_ID_PROPERTY, columnDefinition = "uuid") 77 @Column(name = ModelConstants.DEVICE_FIRMWARE_ID_PROPERTY, columnDefinition = "uuid")
78 private UUID firmwareId; 78 private UUID firmwareId;
79 79
  80 + @Column(name = ModelConstants.DEVICE_SOFTWARE_ID_PROPERTY, columnDefinition = "uuid")
  81 + private UUID softwareId;
  82 +
80 @Type(type = "jsonb") 83 @Type(type = "jsonb")
81 @Column(name = ModelConstants.DEVICE_DEVICE_DATA_PROPERTY, columnDefinition = "jsonb") 84 @Column(name = ModelConstants.DEVICE_DEVICE_DATA_PROPERTY, columnDefinition = "jsonb")
82 private JsonNode deviceData; 85 private JsonNode deviceData;
@@ -102,6 +105,9 @@ public abstract class AbstractDeviceEntity<T extends Device> extends BaseSqlEnti @@ -102,6 +105,9 @@ public abstract class AbstractDeviceEntity<T extends Device> extends BaseSqlEnti
102 if (device.getFirmwareId() != null) { 105 if (device.getFirmwareId() != null) {
103 this.firmwareId = device.getFirmwareId().getId(); 106 this.firmwareId = device.getFirmwareId().getId();
104 } 107 }
  108 + if (device.getSoftwareId() != null) {
  109 + this.softwareId = device.getSoftwareId().getId();
  110 + }
105 this.deviceData = JacksonUtil.convertValue(device.getDeviceData(), ObjectNode.class); 111 this.deviceData = JacksonUtil.convertValue(device.getDeviceData(), ObjectNode.class);
106 this.name = device.getName(); 112 this.name = device.getName();
107 this.type = device.getType(); 113 this.type = device.getType();
@@ -122,6 +128,7 @@ public abstract class AbstractDeviceEntity<T extends Device> extends BaseSqlEnti @@ -122,6 +128,7 @@ public abstract class AbstractDeviceEntity<T extends Device> extends BaseSqlEnti
122 this.searchText = deviceEntity.getSearchText(); 128 this.searchText = deviceEntity.getSearchText();
123 this.additionalInfo = deviceEntity.getAdditionalInfo(); 129 this.additionalInfo = deviceEntity.getAdditionalInfo();
124 this.firmwareId = deviceEntity.getFirmwareId(); 130 this.firmwareId = deviceEntity.getFirmwareId();
  131 + this.softwareId = deviceEntity.getSoftwareId();
125 } 132 }
126 133
127 @Override 134 @Override
@@ -149,6 +156,9 @@ public abstract class AbstractDeviceEntity<T extends Device> extends BaseSqlEnti @@ -149,6 +156,9 @@ public abstract class AbstractDeviceEntity<T extends Device> extends BaseSqlEnti
149 if (firmwareId != null) { 156 if (firmwareId != null) {
150 device.setFirmwareId(new FirmwareId(firmwareId)); 157 device.setFirmwareId(new FirmwareId(firmwareId));
151 } 158 }
  159 + if (softwareId != null) {
  160 + device.setSoftwareId(new FirmwareId(softwareId));
  161 + }
152 device.setDeviceData(JacksonUtil.convertValue(deviceData, DeviceData.class)); 162 device.setDeviceData(JacksonUtil.convertValue(deviceData, DeviceData.class));
153 device.setName(name); 163 device.setName(name);
154 device.setType(type); 164 device.setType(type);
@@ -21,9 +21,10 @@ import lombok.Data; @@ -21,9 +21,10 @@ import lombok.Data;
21 import lombok.EqualsAndHashCode; 21 import lombok.EqualsAndHashCode;
22 import org.hibernate.annotations.Type; 22 import org.hibernate.annotations.Type;
23 import org.hibernate.annotations.TypeDef; 23 import org.hibernate.annotations.TypeDef;
  24 +import org.thingsboard.common.util.JacksonUtil;
24 import org.thingsboard.server.common.data.DeviceProfile; 25 import org.thingsboard.server.common.data.DeviceProfile;
25 -import org.thingsboard.server.common.data.DeviceProfileType;  
26 import org.thingsboard.server.common.data.DeviceProfileProvisionType; 26 import org.thingsboard.server.common.data.DeviceProfileProvisionType;
  27 +import org.thingsboard.server.common.data.DeviceProfileType;
27 import org.thingsboard.server.common.data.DeviceTransportType; 28 import org.thingsboard.server.common.data.DeviceTransportType;
28 import org.thingsboard.server.common.data.device.profile.DeviceProfileData; 29 import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
29 import org.thingsboard.server.common.data.id.DeviceProfileId; 30 import org.thingsboard.server.common.data.id.DeviceProfileId;
@@ -33,7 +34,6 @@ import org.thingsboard.server.common.data.id.TenantId; @@ -33,7 +34,6 @@ import org.thingsboard.server.common.data.id.TenantId;
33 import org.thingsboard.server.dao.model.BaseSqlEntity; 34 import org.thingsboard.server.dao.model.BaseSqlEntity;
34 import org.thingsboard.server.dao.model.ModelConstants; 35 import org.thingsboard.server.dao.model.ModelConstants;
35 import org.thingsboard.server.dao.model.SearchTextEntity; 36 import org.thingsboard.server.dao.model.SearchTextEntity;
36 -import org.thingsboard.common.util.JacksonUtil;  
37 import org.thingsboard.server.dao.util.mapping.JsonBinaryType; 37 import org.thingsboard.server.dao.util.mapping.JsonBinaryType;
38 38
39 import javax.persistence.Column; 39 import javax.persistence.Column;
@@ -87,12 +87,15 @@ public final class DeviceProfileEntity extends BaseSqlEntity<DeviceProfile> impl @@ -87,12 +87,15 @@ public final class DeviceProfileEntity extends BaseSqlEntity<DeviceProfile> impl
87 @Column(name = ModelConstants.DEVICE_PROFILE_PROFILE_DATA_PROPERTY, columnDefinition = "jsonb") 87 @Column(name = ModelConstants.DEVICE_PROFILE_PROFILE_DATA_PROPERTY, columnDefinition = "jsonb")
88 private JsonNode profileData; 88 private JsonNode profileData;
89 89
90 - @Column(name=ModelConstants.DEVICE_PROFILE_PROVISION_DEVICE_KEY) 90 + @Column(name = ModelConstants.DEVICE_PROFILE_PROVISION_DEVICE_KEY)
91 private String provisionDeviceKey; 91 private String provisionDeviceKey;
92 92
93 - @Column(name=ModelConstants.DEVICE_PROFILE_FIRMWARE_ID_PROPERTY) 93 + @Column(name = ModelConstants.DEVICE_PROFILE_FIRMWARE_ID_PROPERTY)
94 private UUID firmwareId; 94 private UUID firmwareId;
95 95
  96 + @Column(name = ModelConstants.DEVICE_PROFILE_SOFTWARE_ID_PROPERTY)
  97 + private UUID softwareId;
  98 +
96 public DeviceProfileEntity() { 99 public DeviceProfileEntity() {
97 super(); 100 super();
98 } 101 }
@@ -120,6 +123,9 @@ public final class DeviceProfileEntity extends BaseSqlEntity<DeviceProfile> impl @@ -120,6 +123,9 @@ public final class DeviceProfileEntity extends BaseSqlEntity<DeviceProfile> impl
120 if (deviceProfile.getFirmwareId() != null) { 123 if (deviceProfile.getFirmwareId() != null) {
121 this.firmwareId = deviceProfile.getFirmwareId().getId(); 124 this.firmwareId = deviceProfile.getFirmwareId().getId();
122 } 125 }
  126 + if (deviceProfile.getSoftwareId() != null) {
  127 + this.firmwareId = deviceProfile.getSoftwareId().getId();
  128 + }
123 } 129 }
124 130
125 @Override 131 @Override
@@ -160,6 +166,10 @@ public final class DeviceProfileEntity extends BaseSqlEntity<DeviceProfile> impl @@ -160,6 +166,10 @@ public final class DeviceProfileEntity extends BaseSqlEntity<DeviceProfile> impl
160 deviceProfile.setFirmwareId(new FirmwareId(firmwareId)); 166 deviceProfile.setFirmwareId(new FirmwareId(firmwareId));
161 } 167 }
162 168
  169 + if (softwareId != null) {
  170 + deviceProfile.setSoftwareId(new FirmwareId(softwareId));
  171 + }
  172 +
163 return deviceProfile; 173 return deviceProfile;
164 } 174 }
165 } 175 }
@@ -21,6 +21,8 @@ import lombok.EqualsAndHashCode; @@ -21,6 +21,8 @@ import lombok.EqualsAndHashCode;
21 import org.hibernate.annotations.Type; 21 import org.hibernate.annotations.Type;
22 import org.hibernate.annotations.TypeDef; 22 import org.hibernate.annotations.TypeDef;
23 import org.thingsboard.server.common.data.Firmware; 23 import org.thingsboard.server.common.data.Firmware;
  24 +import org.thingsboard.server.common.data.firmware.FirmwareType;
  25 +import org.thingsboard.server.common.data.id.DeviceProfileId;
24 import org.thingsboard.server.common.data.id.FirmwareId; 26 import org.thingsboard.server.common.data.id.FirmwareId;
25 import org.thingsboard.server.common.data.id.TenantId; 27 import org.thingsboard.server.common.data.id.TenantId;
26 import org.thingsboard.server.dao.model.BaseSqlEntity; 28 import org.thingsboard.server.dao.model.BaseSqlEntity;
@@ -30,6 +32,8 @@ import org.thingsboard.server.dao.util.mapping.JsonStringType; @@ -30,6 +32,8 @@ import org.thingsboard.server.dao.util.mapping.JsonStringType;
30 32
31 import javax.persistence.Column; 33 import javax.persistence.Column;
32 import javax.persistence.Entity; 34 import javax.persistence.Entity;
  35 +import javax.persistence.EnumType;
  36 +import javax.persistence.Enumerated;
33 import javax.persistence.Lob; 37 import javax.persistence.Lob;
34 import javax.persistence.Table; 38 import javax.persistence.Table;
35 import java.nio.ByteBuffer; 39 import java.nio.ByteBuffer;
@@ -40,10 +44,12 @@ import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_CHECKSUM_ @@ -40,10 +44,12 @@ import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_CHECKSUM_
40 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_CONTENT_TYPE_COLUMN; 44 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_CONTENT_TYPE_COLUMN;
41 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_DATA_COLUMN; 45 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_DATA_COLUMN;
42 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_DATA_SIZE_COLUMN; 46 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_DATA_SIZE_COLUMN;
  47 +import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_DEVICE_PROFILE_ID_COLUMN;
43 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_FILE_NAME_COLUMN; 48 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_FILE_NAME_COLUMN;
44 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TABLE_NAME; 49 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TABLE_NAME;
45 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TENANT_ID_COLUMN; 50 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TENANT_ID_COLUMN;
46 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TITLE_COLUMN; 51 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TITLE_COLUMN;
  52 +import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TYPE_COLUMN;
47 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_VERSION_COLUMN; 53 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_VERSION_COLUMN;
48 import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY; 54 import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY;
49 55
@@ -57,6 +63,13 @@ public class FirmwareEntity extends BaseSqlEntity<Firmware> implements SearchTex @@ -57,6 +63,13 @@ public class FirmwareEntity extends BaseSqlEntity<Firmware> implements SearchTex
57 @Column(name = FIRMWARE_TENANT_ID_COLUMN) 63 @Column(name = FIRMWARE_TENANT_ID_COLUMN)
58 private UUID tenantId; 64 private UUID tenantId;
59 65
  66 + @Column(name = FIRMWARE_DEVICE_PROFILE_ID_COLUMN)
  67 + private UUID deviceProfileId;
  68 +
  69 + @Enumerated(EnumType.STRING)
  70 + @Column(name = FIRMWARE_TYPE_COLUMN)
  71 + private FirmwareType type;
  72 +
60 @Column(name = FIRMWARE_TITLE_COLUMN) 73 @Column(name = FIRMWARE_TITLE_COLUMN)
61 private String title; 74 private String title;
62 75
@@ -97,6 +110,10 @@ public class FirmwareEntity extends BaseSqlEntity<Firmware> implements SearchTex @@ -97,6 +110,10 @@ public class FirmwareEntity extends BaseSqlEntity<Firmware> implements SearchTex
97 this.createdTime = firmware.getCreatedTime(); 110 this.createdTime = firmware.getCreatedTime();
98 this.setUuid(firmware.getUuidId()); 111 this.setUuid(firmware.getUuidId());
99 this.tenantId = firmware.getTenantId().getId(); 112 this.tenantId = firmware.getTenantId().getId();
  113 + if (firmware.getDeviceProfileId() != null) {
  114 + this.deviceProfileId = firmware.getDeviceProfileId().getId();
  115 + }
  116 + this.type = firmware.getType();
100 this.title = firmware.getTitle(); 117 this.title = firmware.getTitle();
101 this.version = firmware.getVersion(); 118 this.version = firmware.getVersion();
102 this.fileName = firmware.getFileName(); 119 this.fileName = firmware.getFileName();
@@ -123,6 +140,10 @@ public class FirmwareEntity extends BaseSqlEntity<Firmware> implements SearchTex @@ -123,6 +140,10 @@ public class FirmwareEntity extends BaseSqlEntity<Firmware> implements SearchTex
123 Firmware firmware = new Firmware(new FirmwareId(id)); 140 Firmware firmware = new Firmware(new FirmwareId(id));
124 firmware.setCreatedTime(createdTime); 141 firmware.setCreatedTime(createdTime);
125 firmware.setTenantId(new TenantId(tenantId)); 142 firmware.setTenantId(new TenantId(tenantId));
  143 + if (deviceProfileId != null) {
  144 + firmware.setDeviceProfileId(new DeviceProfileId(deviceProfileId));
  145 + }
  146 + firmware.setType(type);
126 firmware.setTitle(title); 147 firmware.setTitle(title);
127 firmware.setVersion(version); 148 firmware.setVersion(version);
128 firmware.setFileName(fileName); 149 firmware.setFileName(fileName);
@@ -22,6 +22,8 @@ import org.hibernate.annotations.Type; @@ -22,6 +22,8 @@ import org.hibernate.annotations.Type;
22 import org.hibernate.annotations.TypeDef; 22 import org.hibernate.annotations.TypeDef;
23 import org.thingsboard.common.util.JacksonUtil; 23 import org.thingsboard.common.util.JacksonUtil;
24 import org.thingsboard.server.common.data.FirmwareInfo; 24 import org.thingsboard.server.common.data.FirmwareInfo;
  25 +import org.thingsboard.server.common.data.firmware.FirmwareType;
  26 +import org.thingsboard.server.common.data.id.DeviceProfileId;
25 import org.thingsboard.server.common.data.id.FirmwareId; 27 import org.thingsboard.server.common.data.id.FirmwareId;
26 import org.thingsboard.server.common.data.id.TenantId; 28 import org.thingsboard.server.common.data.id.TenantId;
27 import org.thingsboard.server.dao.model.BaseSqlEntity; 29 import org.thingsboard.server.dao.model.BaseSqlEntity;
@@ -31,6 +33,8 @@ import org.thingsboard.server.dao.util.mapping.JsonStringType; @@ -31,6 +33,8 @@ import org.thingsboard.server.dao.util.mapping.JsonStringType;
31 33
32 import javax.persistence.Column; 34 import javax.persistence.Column;
33 import javax.persistence.Entity; 35 import javax.persistence.Entity;
  36 +import javax.persistence.EnumType;
  37 +import javax.persistence.Enumerated;
34 import javax.persistence.Table; 38 import javax.persistence.Table;
35 import javax.persistence.Transient; 39 import javax.persistence.Transient;
36 import java.util.UUID; 40 import java.util.UUID;
@@ -38,13 +42,13 @@ import java.util.UUID; @@ -38,13 +42,13 @@ import java.util.UUID;
38 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_CHECKSUM_ALGORITHM_COLUMN; 42 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_CHECKSUM_ALGORITHM_COLUMN;
39 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_CHECKSUM_COLUMN; 43 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_CHECKSUM_COLUMN;
40 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_CONTENT_TYPE_COLUMN; 44 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_CONTENT_TYPE_COLUMN;
41 -import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_DATA_COLUMN;  
42 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_DATA_SIZE_COLUMN; 45 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_DATA_SIZE_COLUMN;
  46 +import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_DEVICE_PROFILE_ID_COLUMN;
43 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_FILE_NAME_COLUMN; 47 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_FILE_NAME_COLUMN;
44 -import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_HAS_DATA_PROPERTY;  
45 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TABLE_NAME; 48 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TABLE_NAME;
46 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TENANT_ID_COLUMN; 49 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TENANT_ID_COLUMN;
47 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TITLE_COLUMN; 50 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TITLE_COLUMN;
  51 +import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TYPE_COLUMN;
48 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_VERSION_COLUMN; 52 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_VERSION_COLUMN;
49 import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY; 53 import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY;
50 54
@@ -58,6 +62,13 @@ public class FirmwareInfoEntity extends BaseSqlEntity<FirmwareInfo> implements S @@ -58,6 +62,13 @@ public class FirmwareInfoEntity extends BaseSqlEntity<FirmwareInfo> implements S
58 @Column(name = FIRMWARE_TENANT_ID_COLUMN) 62 @Column(name = FIRMWARE_TENANT_ID_COLUMN)
59 private UUID tenantId; 63 private UUID tenantId;
60 64
  65 + @Column(name = FIRMWARE_DEVICE_PROFILE_ID_COLUMN)
  66 + private UUID deviceProfileId;
  67 +
  68 + @Enumerated(EnumType.STRING)
  69 + @Column(name = FIRMWARE_TYPE_COLUMN)
  70 + private FirmwareType type;
  71 +
61 @Column(name = FIRMWARE_TITLE_COLUMN) 72 @Column(name = FIRMWARE_TITLE_COLUMN)
62 private String title; 73 private String title;
63 74
@@ -97,6 +108,10 @@ public class FirmwareInfoEntity extends BaseSqlEntity<FirmwareInfo> implements S @@ -97,6 +108,10 @@ public class FirmwareInfoEntity extends BaseSqlEntity<FirmwareInfo> implements S
97 this.createdTime = firmware.getCreatedTime(); 108 this.createdTime = firmware.getCreatedTime();
98 this.setUuid(firmware.getUuidId()); 109 this.setUuid(firmware.getUuidId());
99 this.tenantId = firmware.getTenantId().getId(); 110 this.tenantId = firmware.getTenantId().getId();
  111 + this.type = firmware.getType();
  112 + if (firmware.getDeviceProfileId() != null) {
  113 + this.deviceProfileId = firmware.getDeviceProfileId().getId();
  114 + }
100 this.title = firmware.getTitle(); 115 this.title = firmware.getTitle();
101 this.version = firmware.getVersion(); 116 this.version = firmware.getVersion();
102 this.fileName = firmware.getFileName(); 117 this.fileName = firmware.getFileName();
@@ -107,12 +122,14 @@ public class FirmwareInfoEntity extends BaseSqlEntity<FirmwareInfo> implements S @@ -107,12 +122,14 @@ public class FirmwareInfoEntity extends BaseSqlEntity<FirmwareInfo> implements S
107 this.additionalInfo = firmware.getAdditionalInfo(); 122 this.additionalInfo = firmware.getAdditionalInfo();
108 } 123 }
109 124
110 - public FirmwareInfoEntity(UUID id, long createdTime, UUID tenantId, String title, String version, 125 + public FirmwareInfoEntity(UUID id, long createdTime, UUID tenantId, UUID deviceProfileId, FirmwareType type, String title, String version,
111 String fileName, String contentType, String checksumAlgorithm, String checksum, Long dataSize, 126 String fileName, String contentType, String checksumAlgorithm, String checksum, Long dataSize,
112 Object additionalInfo, boolean hasData) { 127 Object additionalInfo, boolean hasData) {
113 this.id = id; 128 this.id = id;
114 this.createdTime = createdTime; 129 this.createdTime = createdTime;
115 this.tenantId = tenantId; 130 this.tenantId = tenantId;
  131 + this.deviceProfileId = deviceProfileId;
  132 + this.type = type;
116 this.title = title; 133 this.title = title;
117 this.version = version; 134 this.version = version;
118 this.fileName = fileName; 135 this.fileName = fileName;
@@ -139,6 +156,10 @@ public class FirmwareInfoEntity extends BaseSqlEntity<FirmwareInfo> implements S @@ -139,6 +156,10 @@ public class FirmwareInfoEntity extends BaseSqlEntity<FirmwareInfo> implements S
139 FirmwareInfo firmware = new FirmwareInfo(new FirmwareId(id)); 156 FirmwareInfo firmware = new FirmwareInfo(new FirmwareId(id));
140 firmware.setCreatedTime(createdTime); 157 firmware.setCreatedTime(createdTime);
141 firmware.setTenantId(new TenantId(tenantId)); 158 firmware.setTenantId(new TenantId(tenantId));
  159 + if (deviceProfileId != null) {
  160 + firmware.setDeviceProfileId(new DeviceProfileId(deviceProfileId));
  161 + }
  162 + firmware.setType(type);
142 firmware.setTitle(title); 163 firmware.setTitle(title);
143 firmware.setVersion(version); 164 firmware.setVersion(version);
144 firmware.setFileName(fileName); 165 firmware.setFileName(fileName);
@@ -104,6 +104,15 @@ public interface DeviceRepository extends PagingAndSortingRepository<DeviceEntit @@ -104,6 +104,15 @@ public interface DeviceRepository extends PagingAndSortingRepository<DeviceEntit
104 @Param("textSearch") String textSearch, 104 @Param("textSearch") String textSearch,
105 Pageable pageable); 105 Pageable pageable);
106 106
  107 + @Query("SELECT d FROM DeviceEntity d WHERE d.tenantId = :tenantId " +
  108 + "AND d.type = :type " +
  109 + "AND d.softwareId = null " +
  110 + "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%'))")
  111 + Page<DeviceEntity> findByTenantIdAndTypeAndSoftwareIdIsNull(@Param("tenantId") UUID tenantId,
  112 + @Param("type") String type,
  113 + @Param("textSearch") String textSearch,
  114 + Pageable pageable);
  115 +
107 @Query("SELECT new org.thingsboard.server.dao.model.sql.DeviceInfoEntity(d, c.title, c.additionalInfo, p.name) " + 116 @Query("SELECT new org.thingsboard.server.dao.model.sql.DeviceInfoEntity(d, c.title, c.additionalInfo, p.name) " +
108 "FROM DeviceEntity d " + 117 "FROM DeviceEntity d " +
109 "LEFT JOIN CustomerEntity c on c.id = d.customerId " + 118 "LEFT JOIN CustomerEntity c on c.id = d.customerId " +
@@ -165,6 +165,16 @@ public class JpaDeviceDao extends JpaAbstractSearchTextDao<DeviceEntity, Device> @@ -165,6 +165,16 @@ public class JpaDeviceDao extends JpaAbstractSearchTextDao<DeviceEntity, Device>
165 } 165 }
166 166
167 @Override 167 @Override
  168 + public PageData<Device> findDevicesByTenantIdAndTypeAndEmptySoftware(UUID tenantId, String type, PageLink pageLink) {
  169 + return DaoUtil.toPageData(
  170 + deviceRepository.findByTenantIdAndTypeAndSoftwareIdIsNull(
  171 + tenantId,
  172 + type,
  173 + Objects.toString(pageLink.getTextSearch(), ""),
  174 + DaoUtil.toPageable(pageLink)));
  175 + }
  176 +
  177 + @Override
168 public PageData<DeviceInfo> findDeviceInfosByTenantIdAndType(UUID tenantId, String type, PageLink pageLink) { 178 public PageData<DeviceInfo> findDeviceInfosByTenantIdAndType(UUID tenantId, String type, PageLink pageLink) {
169 return DaoUtil.toPageData( 179 return DaoUtil.toPageData(
170 deviceRepository.findDeviceInfosByTenantIdAndType( 180 deviceRepository.findDeviceInfosByTenantIdAndType(
@@ -20,27 +20,41 @@ import org.springframework.data.domain.Pageable; @@ -20,27 +20,41 @@ import org.springframework.data.domain.Pageable;
20 import org.springframework.data.jpa.repository.Query; 20 import org.springframework.data.jpa.repository.Query;
21 import org.springframework.data.repository.CrudRepository; 21 import org.springframework.data.repository.CrudRepository;
22 import org.springframework.data.repository.query.Param; 22 import org.springframework.data.repository.query.Param;
  23 +import org.thingsboard.server.common.data.firmware.FirmwareType;
23 import org.thingsboard.server.dao.model.sql.FirmwareInfoEntity; 24 import org.thingsboard.server.dao.model.sql.FirmwareInfoEntity;
24 25
25 import java.util.UUID; 26 import java.util.UUID;
26 27
27 public interface FirmwareInfoRepository extends CrudRepository<FirmwareInfoEntity, UUID> { 28 public interface FirmwareInfoRepository extends CrudRepository<FirmwareInfoEntity, UUID> {
28 - @Query("SELECT new FirmwareInfoEntity(f.id, f.createdTime, f.tenantId, f.title, f.version, f.fileName, f.contentType, f.checksumAlgorithm, f.checksum, f.dataSize, f.additionalInfo, f.data IS NOT NULL) FROM FirmwareEntity f WHERE " + 29 + @Query("SELECT new FirmwareInfoEntity(f.id, f.createdTime, f.tenantId, f.deviceProfileId, f.type, f.title, f.version, f.fileName, f.contentType, f.checksumAlgorithm, f.checksum, f.dataSize, f.additionalInfo, f.data IS NOT NULL) FROM FirmwareEntity f WHERE " +
29 "f.tenantId = :tenantId " + 30 "f.tenantId = :tenantId " +
30 "AND LOWER(f.searchText) LIKE LOWER(CONCAT(:searchText, '%'))") 31 "AND LOWER(f.searchText) LIKE LOWER(CONCAT(:searchText, '%'))")
31 Page<FirmwareInfoEntity> findAllByTenantId(@Param("tenantId") UUID tenantId, 32 Page<FirmwareInfoEntity> findAllByTenantId(@Param("tenantId") UUID tenantId,
32 @Param("searchText") String searchText, 33 @Param("searchText") String searchText,
33 Pageable pageable); 34 Pageable pageable);
34 35
35 - @Query("SELECT new FirmwareInfoEntity(f.id, f.createdTime, f.tenantId, f.title, f.version, f.fileName, f.contentType, f.checksumAlgorithm, f.checksum, f.dataSize, f.additionalInfo, f.data IS NOT NULL) FROM FirmwareEntity f WHERE " + 36 + @Query("SELECT new FirmwareInfoEntity(f.id, f.createdTime, f.tenantId, f.deviceProfileId, f.type, f.title, f.version, f.fileName, f.contentType, f.checksumAlgorithm, f.checksum, f.dataSize, f.additionalInfo, f.data IS NOT NULL) FROM FirmwareEntity f WHERE " +
36 "f.tenantId = :tenantId " + 37 "f.tenantId = :tenantId " +
  38 + "AND f.deviceProfileId = :deviceProfileId " +
  39 + "AND f.type = :type " +
37 "AND ((f.data IS NOT NULL AND :hasData = true) OR (f.data IS NULL AND :hasData = false ))" + 40 "AND ((f.data IS NOT NULL AND :hasData = true) OR (f.data IS NULL AND :hasData = false ))" +
38 "AND LOWER(f.searchText) LIKE LOWER(CONCAT(:searchText, '%'))") 41 "AND LOWER(f.searchText) LIKE LOWER(CONCAT(:searchText, '%'))")
39 - Page<FirmwareInfoEntity> findAllByTenantIdAndHasData(@Param("tenantId") UUID tenantId,  
40 - @Param("hasData") boolean hasData,  
41 - @Param("searchText") String searchText,  
42 - Pageable pageable); 42 + Page<FirmwareInfoEntity> findAllByTenantIdAndTypeAndDeviceProfileIdAndHasData(@Param("tenantId") UUID tenantId,
  43 + @Param("deviceProfileId") UUID deviceProfileId,
  44 + @Param("type") FirmwareType type,
  45 + @Param("hasData") boolean hasData,
  46 + @Param("searchText") String searchText,
  47 + Pageable pageable);
43 48
44 - @Query("SELECT new FirmwareInfoEntity(f.id, f.createdTime, f.tenantId, f.title, f.version, f.fileName, f.contentType, f.checksumAlgorithm, f.checksum, f.dataSize, f.additionalInfo, f.data IS NOT NULL) FROM FirmwareEntity f WHERE f.id = :id") 49 + @Query("SELECT new FirmwareInfoEntity(f.id, f.createdTime, f.tenantId, f.deviceProfileId, f.type, f.title, f.version, f.fileName, f.contentType, f.checksumAlgorithm, f.checksum, f.dataSize, f.additionalInfo, f.data IS NOT NULL) FROM FirmwareEntity f WHERE f.id = :id")
45 FirmwareInfoEntity findFirmwareInfoById(@Param("id") UUID id); 50 FirmwareInfoEntity findFirmwareInfoById(@Param("id") UUID id);
  51 +
  52 + @Query(value = "SELECT exists(SELECT * " +
  53 + "FROM device_profile AS dp " +
  54 + "LEFT JOIN device AS d ON dp.id = d.device_profile_id " +
  55 + "WHERE dp.id = :deviceProfileId AND " +
  56 + "(('FIRMWARE' = :type AND (dp.firmware_id = :firmwareId OR d.firmware_id = :firmwareId)) " +
  57 + "OR ('SOFTWARE' = :type AND (dp.software_id = :firmwareId or d.software_id = :firmwareId))))", nativeQuery = true)
  58 + boolean isFirmwareUsed(@Param("firmwareId") UUID firmwareId, @Param("deviceProfileId") UUID deviceProfileId, @Param("type") String type);
  59 +
46 } 60 }
@@ -20,6 +20,9 @@ import org.springframework.beans.factory.annotation.Autowired; @@ -20,6 +20,9 @@ import org.springframework.beans.factory.annotation.Autowired;
20 import org.springframework.data.repository.CrudRepository; 20 import org.springframework.data.repository.CrudRepository;
21 import org.springframework.stereotype.Component; 21 import org.springframework.stereotype.Component;
22 import org.thingsboard.server.common.data.FirmwareInfo; 22 import org.thingsboard.server.common.data.FirmwareInfo;
  23 +import org.thingsboard.server.common.data.firmware.FirmwareType;
  24 +import org.thingsboard.server.common.data.id.DeviceProfileId;
  25 +import org.thingsboard.server.common.data.id.FirmwareId;
23 import org.thingsboard.server.common.data.id.TenantId; 26 import org.thingsboard.server.common.data.id.TenantId;
24 import org.thingsboard.server.common.data.page.PageData; 27 import org.thingsboard.server.common.data.page.PageData;
25 import org.thingsboard.server.common.data.page.PageLink; 28 import org.thingsboard.server.common.data.page.PageLink;
@@ -73,12 +76,19 @@ public class JpaFirmwareInfoDao extends JpaAbstractSearchTextDao<FirmwareInfoEnt @@ -73,12 +76,19 @@ public class JpaFirmwareInfoDao extends JpaAbstractSearchTextDao<FirmwareInfoEnt
73 } 76 }
74 77
75 @Override 78 @Override
76 - public PageData<FirmwareInfo> findFirmwareInfoByTenantIdAndHasData(TenantId tenantId, boolean hasData, PageLink pageLink) { 79 + public PageData<FirmwareInfo> findFirmwareInfoByTenantIdAndDeviceProfileIdAndTypeAndHasData(TenantId tenantId, DeviceProfileId deviceProfileId, FirmwareType firmwareType, boolean hasData, PageLink pageLink) {
77 return DaoUtil.toPageData(firmwareInfoRepository 80 return DaoUtil.toPageData(firmwareInfoRepository
78 - .findAllByTenantIdAndHasData( 81 + .findAllByTenantIdAndTypeAndDeviceProfileIdAndHasData(
79 tenantId.getId(), 82 tenantId.getId(),
  83 + deviceProfileId.getId(),
  84 + firmwareType,
80 hasData, 85 hasData,
81 Objects.toString(pageLink.getTextSearch(), ""), 86 Objects.toString(pageLink.getTextSearch(), ""),
82 DaoUtil.toPageable(pageLink))); 87 DaoUtil.toPageable(pageLink)));
83 } 88 }
  89 +
  90 + @Override
  91 + public boolean isFirmwareUsed(FirmwareId firmwareId, FirmwareType type, DeviceProfileId deviceProfileId) {
  92 + return firmwareInfoRepository.isFirmwareUsed(firmwareId.getId(), deviceProfileId.getId(), type.name());
  93 + }
84 } 94 }
@@ -162,6 +162,8 @@ CREATE TABLE IF NOT EXISTS firmware ( @@ -162,6 +162,8 @@ CREATE TABLE IF NOT EXISTS firmware (
162 id uuid NOT NULL CONSTRAINT firmware_pkey PRIMARY KEY, 162 id uuid NOT NULL CONSTRAINT firmware_pkey PRIMARY KEY,
163 created_time bigint NOT NULL, 163 created_time bigint NOT NULL,
164 tenant_id uuid NOT NULL, 164 tenant_id uuid NOT NULL,
  165 + device_profile_id uuid ,
  166 + type varchar(32) NOT NULL,
165 title varchar(255) NOT NULL, 167 title varchar(255) NOT NULL,
166 version varchar(255) NOT NULL, 168 version varchar(255) NOT NULL,
167 file_name varchar(255), 169 file_name varchar(255),
@@ -188,13 +190,15 @@ CREATE TABLE IF NOT EXISTS device_profile ( @@ -188,13 +190,15 @@ CREATE TABLE IF NOT EXISTS device_profile (
188 is_default boolean, 190 is_default boolean,
189 tenant_id uuid, 191 tenant_id uuid,
190 firmware_id uuid, 192 firmware_id uuid,
  193 + software_id uuid,
191 default_rule_chain_id uuid, 194 default_rule_chain_id uuid,
192 default_queue_name varchar(255), 195 default_queue_name varchar(255),
193 provision_device_key varchar, 196 provision_device_key varchar,
194 CONSTRAINT device_profile_name_unq_key UNIQUE (tenant_id, name), 197 CONSTRAINT device_profile_name_unq_key UNIQUE (tenant_id, name),
195 CONSTRAINT device_provision_key_unq_key UNIQUE (provision_device_key), 198 CONSTRAINT device_provision_key_unq_key UNIQUE (provision_device_key),
196 CONSTRAINT fk_default_rule_chain_device_profile FOREIGN KEY (default_rule_chain_id) REFERENCES rule_chain(id), 199 CONSTRAINT fk_default_rule_chain_device_profile FOREIGN KEY (default_rule_chain_id) REFERENCES rule_chain(id),
197 - CONSTRAINT fk_firmware_device_profile FOREIGN KEY (firmware_id) REFERENCES firmware(id) 200 + CONSTRAINT fk_firmware_device_profile FOREIGN KEY (firmware_id) REFERENCES firmware(id),
  201 + CONSTRAINT fk_software_device_profile FOREIGN KEY (software_id) REFERENCES firmware(id)
198 ); 202 );
199 203
200 CREATE TABLE IF NOT EXISTS device ( 204 CREATE TABLE IF NOT EXISTS device (
@@ -210,9 +214,11 @@ CREATE TABLE IF NOT EXISTS device ( @@ -210,9 +214,11 @@ CREATE TABLE IF NOT EXISTS device (
210 search_text varchar(255), 214 search_text varchar(255),
211 tenant_id uuid, 215 tenant_id uuid,
212 firmware_id uuid, 216 firmware_id uuid,
  217 + software_id uuid,
213 CONSTRAINT device_name_unq_key UNIQUE (tenant_id, name), 218 CONSTRAINT device_name_unq_key UNIQUE (tenant_id, name),
214 CONSTRAINT fk_device_profile FOREIGN KEY (device_profile_id) REFERENCES device_profile(id), 219 CONSTRAINT fk_device_profile FOREIGN KEY (device_profile_id) REFERENCES device_profile(id),
215 - CONSTRAINT fk_firmware_device FOREIGN KEY (firmware_id) REFERENCES firmware(id) 220 + CONSTRAINT fk_firmware_device FOREIGN KEY (firmware_id) REFERENCES firmware(id),
  221 + CONSTRAINT fk_software_device FOREIGN KEY (software_id) REFERENCES firmware(id)
216 ); 222 );
217 223
218 CREATE TABLE IF NOT EXISTS device_credentials ( 224 CREATE TABLE IF NOT EXISTS device_credentials (
@@ -45,3 +45,4 @@ CREATE INDEX IF NOT EXISTS idx_asset_type ON asset(tenant_id, type); @@ -45,3 +45,4 @@ CREATE INDEX IF NOT EXISTS idx_asset_type ON asset(tenant_id, type);
45 CREATE INDEX IF NOT EXISTS idx_attribute_kv_by_key_and_last_update_ts ON attribute_kv(entity_id, attribute_key, last_update_ts desc); 45 CREATE INDEX IF NOT EXISTS idx_attribute_kv_by_key_and_last_update_ts ON attribute_kv(entity_id, attribute_key, last_update_ts desc);
46 46
47 CREATE INDEX IF NOT EXISTS idx_audit_log_tenant_id_and_created_time ON audit_log(tenant_id, created_time); 47 CREATE INDEX IF NOT EXISTS idx_audit_log_tenant_id_and_created_time ON audit_log(tenant_id, created_time);
  48 +
@@ -180,6 +180,8 @@ CREATE TABLE IF NOT EXISTS firmware ( @@ -180,6 +180,8 @@ CREATE TABLE IF NOT EXISTS firmware (
180 id uuid NOT NULL CONSTRAINT firmware_pkey PRIMARY KEY, 180 id uuid NOT NULL CONSTRAINT firmware_pkey PRIMARY KEY,
181 created_time bigint NOT NULL, 181 created_time bigint NOT NULL,
182 tenant_id uuid NOT NULL, 182 tenant_id uuid NOT NULL,
  183 + device_profile_id uuid ,
  184 + type varchar(32) NOT NULL,
183 title varchar(255) NOT NULL, 185 title varchar(255) NOT NULL,
184 version varchar(255) NOT NULL, 186 version varchar(255) NOT NULL,
185 file_name varchar(255), 187 file_name varchar(255),
@@ -191,6 +193,7 @@ CREATE TABLE IF NOT EXISTS firmware ( @@ -191,6 +193,7 @@ CREATE TABLE IF NOT EXISTS firmware (
191 additional_info varchar, 193 additional_info varchar,
192 search_text varchar(255), 194 search_text varchar(255),
193 CONSTRAINT firmware_tenant_title_version_unq_key UNIQUE (tenant_id, title, version) 195 CONSTRAINT firmware_tenant_title_version_unq_key UNIQUE (tenant_id, title, version)
  196 +-- CONSTRAINT fk_device_profile_firmware FOREIGN KEY (device_profile_id) REFERENCES device_profile(id) ON DELETE CASCADE
194 ); 197 );
195 198
196 CREATE TABLE IF NOT EXISTS device_profile ( 199 CREATE TABLE IF NOT EXISTS device_profile (
@@ -206,15 +209,26 @@ CREATE TABLE IF NOT EXISTS device_profile ( @@ -206,15 +209,26 @@ CREATE TABLE IF NOT EXISTS device_profile (
206 is_default boolean, 209 is_default boolean,
207 tenant_id uuid, 210 tenant_id uuid,
208 firmware_id uuid, 211 firmware_id uuid,
  212 + software_id uuid,
209 default_rule_chain_id uuid, 213 default_rule_chain_id uuid,
210 default_queue_name varchar(255), 214 default_queue_name varchar(255),
211 provision_device_key varchar, 215 provision_device_key varchar,
212 CONSTRAINT device_profile_name_unq_key UNIQUE (tenant_id, name), 216 CONSTRAINT device_profile_name_unq_key UNIQUE (tenant_id, name),
213 CONSTRAINT device_provision_key_unq_key UNIQUE (provision_device_key), 217 CONSTRAINT device_provision_key_unq_key UNIQUE (provision_device_key),
214 CONSTRAINT fk_default_rule_chain_device_profile FOREIGN KEY (default_rule_chain_id) REFERENCES rule_chain(id), 218 CONSTRAINT fk_default_rule_chain_device_profile FOREIGN KEY (default_rule_chain_id) REFERENCES rule_chain(id),
215 - CONSTRAINT fk_firmware_device_profile FOREIGN KEY (firmware_id) REFERENCES firmware(id) 219 + CONSTRAINT fk_firmware_device_profile FOREIGN KEY (firmware_id) REFERENCES firmware(id),
  220 + CONSTRAINT fk_software_device_profile FOREIGN KEY (software_id) REFERENCES firmware(id)
216 ); 221 );
217 222
  223 +-- We will use one-to-many relation in the first release and extend this feature in case of user requests
  224 +-- CREATE TABLE IF NOT EXISTS device_profile_firmware (
  225 +-- device_profile_id uuid NOT NULL,
  226 +-- firmware_id uuid NOT NULL,
  227 +-- CONSTRAINT device_profile_firmware_unq_key UNIQUE (device_profile_id, firmware_id),
  228 +-- CONSTRAINT fk_device_profile_firmware_device_profile FOREIGN KEY (device_profile_id) REFERENCES device_profile(id) ON DELETE CASCADE,
  229 +-- CONSTRAINT fk_device_profile_firmware_firmware FOREIGN KEY (firmware_id) REFERENCES firmware(id) ON DELETE CASCADE,
  230 +-- );
  231 +
218 CREATE TABLE IF NOT EXISTS device ( 232 CREATE TABLE IF NOT EXISTS device (
219 id uuid NOT NULL CONSTRAINT device_pkey PRIMARY KEY, 233 id uuid NOT NULL CONSTRAINT device_pkey PRIMARY KEY,
220 created_time bigint NOT NULL, 234 created_time bigint NOT NULL,
@@ -228,9 +242,11 @@ CREATE TABLE IF NOT EXISTS device ( @@ -228,9 +242,11 @@ CREATE TABLE IF NOT EXISTS device (
228 search_text varchar(255), 242 search_text varchar(255),
229 tenant_id uuid, 243 tenant_id uuid,
230 firmware_id uuid, 244 firmware_id uuid,
  245 + software_id uuid,
231 CONSTRAINT device_name_unq_key UNIQUE (tenant_id, name), 246 CONSTRAINT device_name_unq_key UNIQUE (tenant_id, name),
232 CONSTRAINT fk_device_profile FOREIGN KEY (device_profile_id) REFERENCES device_profile(id), 247 CONSTRAINT fk_device_profile FOREIGN KEY (device_profile_id) REFERENCES device_profile(id),
233 - CONSTRAINT fk_firmware_device FOREIGN KEY (firmware_id) REFERENCES firmware(id) 248 + CONSTRAINT fk_firmware_device FOREIGN KEY (firmware_id) REFERENCES firmware(id),
  249 + CONSTRAINT fk_software_device FOREIGN KEY (software_id) REFERENCES firmware(id)
234 ); 250 );
235 251
236 CREATE TABLE IF NOT EXISTS device_credentials ( 252 CREATE TABLE IF NOT EXISTS device_credentials (
@@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.DeviceProfileInfo; @@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.DeviceProfileInfo;
30 import org.thingsboard.server.common.data.DeviceTransportType; 30 import org.thingsboard.server.common.data.DeviceTransportType;
31 import org.thingsboard.server.common.data.Firmware; 31 import org.thingsboard.server.common.data.Firmware;
32 import org.thingsboard.server.common.data.Tenant; 32 import org.thingsboard.server.common.data.Tenant;
  33 +import org.thingsboard.server.common.data.firmware.FirmwareType;
33 import org.thingsboard.server.common.data.id.TenantId; 34 import org.thingsboard.server.common.data.id.TenantId;
34 import org.thingsboard.server.common.data.page.PageData; 35 import org.thingsboard.server.common.data.page.PageData;
35 import org.thingsboard.server.common.data.page.PageLink; 36 import org.thingsboard.server.common.data.page.PageLink;
@@ -43,6 +44,8 @@ import java.util.concurrent.ExecutionException; @@ -43,6 +44,8 @@ import java.util.concurrent.ExecutionException;
43 import java.util.concurrent.Executors; 44 import java.util.concurrent.Executors;
44 import java.util.stream.Collectors; 45 import java.util.stream.Collectors;
45 46
  47 +import static org.thingsboard.server.common.data.firmware.FirmwareType.FIRMWARE;
  48 +
46 public class BaseDeviceProfileServiceTest extends AbstractServiceTest { 49 public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
47 50
48 private IdComparator<DeviceProfile> idComparator = new IdComparator<>(); 51 private IdComparator<DeviceProfile> idComparator = new IdComparator<>();
@@ -97,6 +100,8 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest { @@ -97,6 +100,8 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
97 100
98 Firmware firmware = new Firmware(); 101 Firmware firmware = new Firmware();
99 firmware.setTenantId(tenantId); 102 firmware.setTenantId(tenantId);
  103 + firmware.setDeviceProfileId(savedDeviceProfile.getId());
  104 + firmware.setType(FIRMWARE);
100 firmware.setTitle("my firmware"); 105 firmware.setTitle("my firmware");
101 firmware.setVersion("v1.0"); 106 firmware.setVersion("v1.0");
102 firmware.setFileName("test.txt"); 107 firmware.setFileName("test.txt");
@@ -20,10 +20,13 @@ import org.apache.commons.lang3.RandomStringUtils; @@ -20,10 +20,13 @@ import org.apache.commons.lang3.RandomStringUtils;
20 import org.junit.After; 20 import org.junit.After;
21 import org.junit.Assert; 21 import org.junit.Assert;
22 import org.junit.Before; 22 import org.junit.Before;
  23 +import org.junit.Rule;
23 import org.junit.Test; 24 import org.junit.Test;
  25 +import org.junit.rules.ExpectedException;
24 import org.thingsboard.server.common.data.Customer; 26 import org.thingsboard.server.common.data.Customer;
25 import org.thingsboard.server.common.data.Device; 27 import org.thingsboard.server.common.data.Device;
26 import org.thingsboard.server.common.data.DeviceInfo; 28 import org.thingsboard.server.common.data.DeviceInfo;
  29 +import org.thingsboard.server.common.data.DeviceProfile;
27 import org.thingsboard.server.common.data.EntitySubtype; 30 import org.thingsboard.server.common.data.EntitySubtype;
28 import org.thingsboard.server.common.data.Firmware; 31 import org.thingsboard.server.common.data.Firmware;
29 import org.thingsboard.server.common.data.Tenant; 32 import org.thingsboard.server.common.data.Tenant;
@@ -42,6 +45,7 @@ import java.util.ArrayList; @@ -42,6 +45,7 @@ import java.util.ArrayList;
42 import java.util.Collections; 45 import java.util.Collections;
43 import java.util.List; 46 import java.util.List;
44 47
  48 +import static org.thingsboard.server.common.data.firmware.FirmwareType.FIRMWARE;
45 import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; 49 import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
46 50
47 public abstract class BaseDeviceServiceTest extends AbstractServiceTest { 51 public abstract class BaseDeviceServiceTest extends AbstractServiceTest {
@@ -66,6 +70,9 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { @@ -66,6 +70,9 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest {
66 tenantProfileService.deleteTenantProfiles(anotherTenantId); 70 tenantProfileService.deleteTenantProfiles(anotherTenantId);
67 } 71 }
68 72
  73 + @Rule
  74 + public ExpectedException thrown = ExpectedException.none();
  75 +
69 @Test 76 @Test
70 public void testSaveDevicesWithoutMaxDeviceLimit() { 77 public void testSaveDevicesWithoutMaxDeviceLimit() {
71 Device device = this.saveDevice(tenantId, "My device"); 78 Device device = this.saveDevice(tenantId, "My device");
@@ -183,6 +190,8 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { @@ -183,6 +190,8 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest {
183 190
184 Firmware firmware = new Firmware(); 191 Firmware firmware = new Firmware();
185 firmware.setTenantId(tenantId); 192 firmware.setTenantId(tenantId);
  193 + firmware.setDeviceProfileId(device.getDeviceProfileId());
  194 + firmware.setType(FIRMWARE);
186 firmware.setTitle("my firmware"); 195 firmware.setTitle("my firmware");
187 firmware.setVersion("v1.0"); 196 firmware.setVersion("v1.0");
188 firmware.setFileName("test.txt"); 197 firmware.setFileName("test.txt");
@@ -198,6 +207,40 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { @@ -198,6 +207,40 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest {
198 Device foundDevice = deviceService.findDeviceById(tenantId, savedDevice.getId()); 207 Device foundDevice = deviceService.findDeviceById(tenantId, savedDevice.getId());
199 Assert.assertEquals(foundDevice.getName(), savedDevice.getName()); 208 Assert.assertEquals(foundDevice.getName(), savedDevice.getName());
200 } 209 }
  210 +
  211 + @Test
  212 + public void testAssignFirmwareToDeviceWithDifferentDeviceProfile() {
  213 + Device device = new Device();
  214 + device.setTenantId(tenantId);
  215 + device.setName("My device");
  216 + device.setType("default");
  217 + Device savedDevice = deviceService.saveDevice(device);
  218 +
  219 + Assert.assertNotNull(savedDevice);
  220 +
  221 + DeviceProfile deviceProfile = createDeviceProfile(tenantId, "New device Profile");
  222 + DeviceProfile savedProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
  223 + Assert.assertNotNull(savedProfile);
  224 +
  225 + Firmware firmware = new Firmware();
  226 + firmware.setTenantId(tenantId);
  227 + firmware.setDeviceProfileId(savedProfile.getId());
  228 + firmware.setType(FIRMWARE);
  229 + firmware.setTitle("my firmware");
  230 + firmware.setVersion("v1.0");
  231 + firmware.setFileName("test.txt");
  232 + firmware.setContentType("text/plain");
  233 + firmware.setChecksumAlgorithm("sha256");
  234 + firmware.setChecksum("4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a");
  235 + firmware.setData(ByteBuffer.wrap(new byte[]{1}));
  236 + Firmware savedFirmware = firmwareService.saveFirmware(firmware);
  237 +
  238 + savedDevice.setFirmwareId(savedFirmware.getId());
  239 +
  240 + thrown.expect(DataValidationException.class);
  241 + thrown.expectMessage("Can't assign firmware with different deviceProfile!");
  242 + deviceService.saveDevice(savedDevice);
  243 + }
201 244
202 @Test(expected = DataValidationException.class) 245 @Test(expected = DataValidationException.class)
203 public void testSaveDeviceWithEmptyName() { 246 public void testSaveDeviceWithEmptyName() {
@@ -19,13 +19,16 @@ import com.datastax.oss.driver.api.core.uuid.Uuids; @@ -19,13 +19,16 @@ import com.datastax.oss.driver.api.core.uuid.Uuids;
19 import org.junit.After; 19 import org.junit.After;
20 import org.junit.Assert; 20 import org.junit.Assert;
21 import org.junit.Before; 21 import org.junit.Before;
  22 +import org.junit.Rule;
22 import org.junit.Test; 23 import org.junit.Test;
  24 +import org.junit.rules.ExpectedException;
23 import org.thingsboard.common.util.JacksonUtil; 25 import org.thingsboard.common.util.JacksonUtil;
24 import org.thingsboard.server.common.data.Device; 26 import org.thingsboard.server.common.data.Device;
25 import org.thingsboard.server.common.data.DeviceProfile; 27 import org.thingsboard.server.common.data.DeviceProfile;
26 import org.thingsboard.server.common.data.Firmware; 28 import org.thingsboard.server.common.data.Firmware;
27 import org.thingsboard.server.common.data.FirmwareInfo; 29 import org.thingsboard.server.common.data.FirmwareInfo;
28 import org.thingsboard.server.common.data.Tenant; 30 import org.thingsboard.server.common.data.Tenant;
  31 +import org.thingsboard.server.common.data.id.DeviceProfileId;
29 import org.thingsboard.server.common.data.id.TenantId; 32 import org.thingsboard.server.common.data.id.TenantId;
30 import org.thingsboard.server.common.data.page.PageData; 33 import org.thingsboard.server.common.data.page.PageData;
31 import org.thingsboard.server.common.data.page.PageLink; 34 import org.thingsboard.server.common.data.page.PageLink;
@@ -36,6 +39,8 @@ import java.util.ArrayList; @@ -36,6 +39,8 @@ import java.util.ArrayList;
36 import java.util.Collections; 39 import java.util.Collections;
37 import java.util.List; 40 import java.util.List;
38 41
  42 +import static org.thingsboard.server.common.data.firmware.FirmwareType.FIRMWARE;
  43 +
39 public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { 44 public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
40 45
41 public static final String TITLE = "My firmware"; 46 public static final String TITLE = "My firmware";
@@ -50,6 +55,8 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -50,6 +55,8 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
50 55
51 private TenantId tenantId; 56 private TenantId tenantId;
52 57
  58 + private DeviceProfileId deviceProfileId;
  59 +
53 @Before 60 @Before
54 public void before() { 61 public void before() {
55 Tenant tenant = new Tenant(); 62 Tenant tenant = new Tenant();
@@ -57,8 +64,16 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -57,8 +64,16 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
57 Tenant savedTenant = tenantService.saveTenant(tenant); 64 Tenant savedTenant = tenantService.saveTenant(tenant);
58 Assert.assertNotNull(savedTenant); 65 Assert.assertNotNull(savedTenant);
59 tenantId = savedTenant.getId(); 66 tenantId = savedTenant.getId();
  67 +
  68 + DeviceProfile deviceProfile = this.createDeviceProfile(tenantId, "Device Profile");
  69 + DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
  70 + Assert.assertNotNull(savedDeviceProfile);
  71 + deviceProfileId = savedDeviceProfile.getId();
60 } 72 }
61 73
  74 + @Rule
  75 + public ExpectedException thrown = ExpectedException.none();
  76 +
62 @After 77 @After
63 public void after() { 78 public void after() {
64 tenantService.deleteTenant(tenantId); 79 tenantService.deleteTenant(tenantId);
@@ -68,6 +83,8 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -68,6 +83,8 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
68 public void testSaveFirmware() { 83 public void testSaveFirmware() {
69 Firmware firmware = new Firmware(); 84 Firmware firmware = new Firmware();
70 firmware.setTenantId(tenantId); 85 firmware.setTenantId(tenantId);
  86 + firmware.setDeviceProfileId(deviceProfileId);
  87 + firmware.setType(FIRMWARE);
71 firmware.setTitle(TITLE); 88 firmware.setTitle(TITLE);
72 firmware.setVersion(VERSION); 89 firmware.setVersion(VERSION);
73 firmware.setFileName(FILE_NAME); 90 firmware.setFileName(FILE_NAME);
@@ -99,6 +116,8 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -99,6 +116,8 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
99 public void testSaveFirmwareInfoAndUpdateWithData() { 116 public void testSaveFirmwareInfoAndUpdateWithData() {
100 FirmwareInfo firmwareInfo = new FirmwareInfo(); 117 FirmwareInfo firmwareInfo = new FirmwareInfo();
101 firmwareInfo.setTenantId(tenantId); 118 firmwareInfo.setTenantId(tenantId);
  119 + firmwareInfo.setDeviceProfileId(deviceProfileId);
  120 + firmwareInfo.setType(FIRMWARE);
102 firmwareInfo.setTitle(TITLE); 121 firmwareInfo.setTitle(TITLE);
103 firmwareInfo.setVersion(VERSION); 122 firmwareInfo.setVersion(VERSION);
104 FirmwareInfo savedFirmwareInfo = firmwareService.saveFirmwareInfo(firmwareInfo); 123 FirmwareInfo savedFirmwareInfo = firmwareService.saveFirmwareInfo(firmwareInfo);
@@ -112,6 +131,8 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -112,6 +131,8 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
112 Firmware firmware = new Firmware(savedFirmwareInfo.getId()); 131 Firmware firmware = new Firmware(savedFirmwareInfo.getId());
113 firmware.setCreatedTime(firmwareInfo.getCreatedTime()); 132 firmware.setCreatedTime(firmwareInfo.getCreatedTime());
114 firmware.setTenantId(tenantId); 133 firmware.setTenantId(tenantId);
  134 + firmware.setDeviceProfileId(deviceProfileId);
  135 + firmware.setType(FIRMWARE);
115 firmware.setTitle(TITLE); 136 firmware.setTitle(TITLE);
116 firmware.setVersion(VERSION); 137 firmware.setVersion(VERSION);
117 firmware.setFileName(FILE_NAME); 138 firmware.setFileName(FILE_NAME);
@@ -135,9 +156,11 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -135,9 +156,11 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
135 firmwareService.deleteFirmware(tenantId, savedFirmwareInfo.getId()); 156 firmwareService.deleteFirmware(tenantId, savedFirmwareInfo.getId());
136 } 157 }
137 158
138 - @Test(expected = DataValidationException.class) 159 + @Test
139 public void testSaveFirmwareWithEmptyTenant() { 160 public void testSaveFirmwareWithEmptyTenant() {
140 Firmware firmware = new Firmware(); 161 Firmware firmware = new Firmware();
  162 + firmware.setDeviceProfileId(deviceProfileId);
  163 + firmware.setType(FIRMWARE);
141 firmware.setTitle(TITLE); 164 firmware.setTitle(TITLE);
142 firmware.setVersion(VERSION); 165 firmware.setVersion(VERSION);
143 firmware.setFileName(FILE_NAME); 166 firmware.setFileName(FILE_NAME);
@@ -145,65 +168,108 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -145,65 +168,108 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
145 firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM); 168 firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM);
146 firmware.setChecksum(CHECKSUM); 169 firmware.setChecksum(CHECKSUM);
147 firmware.setData(DATA); 170 firmware.setData(DATA);
  171 +
  172 + thrown.expect(DataValidationException.class);
  173 + thrown.expectMessage("Firmware should be assigned to tenant!");
148 firmwareService.saveFirmware(firmware); 174 firmwareService.saveFirmware(firmware);
149 } 175 }
150 176
151 - @Test(expected = DataValidationException.class) 177 + @Test
  178 + public void testSaveFirmwareWithEmptyType() {
  179 + Firmware firmware = new Firmware();
  180 + firmware.setTenantId(tenantId);
  181 + firmware.setDeviceProfileId(deviceProfileId);
  182 + firmware.setTitle(TITLE);
  183 + firmware.setVersion(VERSION);
  184 + firmware.setFileName(FILE_NAME);
  185 + firmware.setContentType(CONTENT_TYPE);
  186 + firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM);
  187 + firmware.setChecksum(CHECKSUM);
  188 + firmware.setData(DATA);
  189 +
  190 + thrown.expect(DataValidationException.class);
  191 + thrown.expectMessage("Type should be specified!");
  192 + firmwareService.saveFirmware(firmware);
  193 + }
  194 +
  195 + @Test
152 public void testSaveFirmwareWithEmptyTitle() { 196 public void testSaveFirmwareWithEmptyTitle() {
153 Firmware firmware = new Firmware(); 197 Firmware firmware = new Firmware();
154 firmware.setTenantId(tenantId); 198 firmware.setTenantId(tenantId);
  199 + firmware.setDeviceProfileId(deviceProfileId);
  200 + firmware.setType(FIRMWARE);
155 firmware.setVersion(VERSION); 201 firmware.setVersion(VERSION);
156 firmware.setFileName(FILE_NAME); 202 firmware.setFileName(FILE_NAME);
157 firmware.setContentType(CONTENT_TYPE); 203 firmware.setContentType(CONTENT_TYPE);
158 firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM); 204 firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM);
159 firmware.setChecksum(CHECKSUM); 205 firmware.setChecksum(CHECKSUM);
160 firmware.setData(DATA); 206 firmware.setData(DATA);
  207 +
  208 + thrown.expect(DataValidationException.class);
  209 + thrown.expectMessage("Firmware title should be specified!");
161 firmwareService.saveFirmware(firmware); 210 firmwareService.saveFirmware(firmware);
162 } 211 }
163 212
164 - @Test(expected = DataValidationException.class) 213 + @Test
165 public void testSaveFirmwareWithEmptyFileName() { 214 public void testSaveFirmwareWithEmptyFileName() {
166 Firmware firmware = new Firmware(); 215 Firmware firmware = new Firmware();
167 firmware.setTenantId(tenantId); 216 firmware.setTenantId(tenantId);
  217 + firmware.setDeviceProfileId(deviceProfileId);
  218 + firmware.setType(FIRMWARE);
168 firmware.setTitle(TITLE); 219 firmware.setTitle(TITLE);
169 firmware.setVersion(VERSION); 220 firmware.setVersion(VERSION);
170 firmware.setContentType(CONTENT_TYPE); 221 firmware.setContentType(CONTENT_TYPE);
171 firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM); 222 firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM);
172 firmware.setChecksum(CHECKSUM); 223 firmware.setChecksum(CHECKSUM);
173 firmware.setData(DATA); 224 firmware.setData(DATA);
  225 +
  226 + thrown.expect(DataValidationException.class);
  227 + thrown.expectMessage("Firmware file name should be specified!");
174 firmwareService.saveFirmware(firmware); 228 firmwareService.saveFirmware(firmware);
175 } 229 }
176 230
177 - @Test(expected = DataValidationException.class) 231 + @Test
178 public void testSaveFirmwareWithEmptyContentType() { 232 public void testSaveFirmwareWithEmptyContentType() {
179 Firmware firmware = new Firmware(); 233 Firmware firmware = new Firmware();
180 firmware.setTenantId(tenantId); 234 firmware.setTenantId(tenantId);
  235 + firmware.setDeviceProfileId(deviceProfileId);
  236 + firmware.setType(FIRMWARE);
181 firmware.setTitle(TITLE); 237 firmware.setTitle(TITLE);
182 firmware.setVersion(VERSION); 238 firmware.setVersion(VERSION);
183 firmware.setFileName(FILE_NAME); 239 firmware.setFileName(FILE_NAME);
184 firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM); 240 firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM);
185 firmware.setChecksum(CHECKSUM); 241 firmware.setChecksum(CHECKSUM);
186 firmware.setData(DATA); 242 firmware.setData(DATA);
  243 +
  244 + thrown.expect(DataValidationException.class);
  245 + thrown.expectMessage("Firmware content type should be specified!");
187 firmwareService.saveFirmware(firmware); 246 firmwareService.saveFirmware(firmware);
188 } 247 }
189 248
190 - @Test(expected = DataValidationException.class) 249 + @Test
191 public void testSaveFirmwareWithEmptyData() { 250 public void testSaveFirmwareWithEmptyData() {
192 Firmware firmware = new Firmware(); 251 Firmware firmware = new Firmware();
193 firmware.setTenantId(tenantId); 252 firmware.setTenantId(tenantId);
  253 + firmware.setDeviceProfileId(deviceProfileId);
  254 + firmware.setType(FIRMWARE);
194 firmware.setTitle(TITLE); 255 firmware.setTitle(TITLE);
195 firmware.setVersion(VERSION); 256 firmware.setVersion(VERSION);
196 firmware.setFileName(FILE_NAME); 257 firmware.setFileName(FILE_NAME);
197 firmware.setContentType(CONTENT_TYPE); 258 firmware.setContentType(CONTENT_TYPE);
198 firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM); 259 firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM);
199 firmware.setChecksum(CHECKSUM); 260 firmware.setChecksum(CHECKSUM);
  261 +
  262 + thrown.expect(DataValidationException.class);
  263 + thrown.expectMessage("Firmware data should be specified!");
200 firmwareService.saveFirmware(firmware); 264 firmwareService.saveFirmware(firmware);
201 } 265 }
202 266
203 - @Test(expected = DataValidationException.class) 267 + @Test
204 public void testSaveFirmwareWithInvalidTenant() { 268 public void testSaveFirmwareWithInvalidTenant() {
205 Firmware firmware = new Firmware(); 269 Firmware firmware = new Firmware();
206 firmware.setTenantId(new TenantId(Uuids.timeBased())); 270 firmware.setTenantId(new TenantId(Uuids.timeBased()));
  271 + firmware.setDeviceProfileId(deviceProfileId);
  272 + firmware.setType(FIRMWARE);
207 firmware.setTitle(TITLE); 273 firmware.setTitle(TITLE);
208 firmware.setVersion(VERSION); 274 firmware.setVersion(VERSION);
209 firmware.setFileName(FILE_NAME); 275 firmware.setFileName(FILE_NAME);
@@ -211,41 +277,77 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -211,41 +277,77 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
211 firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM); 277 firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM);
212 firmware.setChecksum(CHECKSUM); 278 firmware.setChecksum(CHECKSUM);
213 firmware.setData(DATA); 279 firmware.setData(DATA);
  280 +
  281 + thrown.expect(DataValidationException.class);
  282 + thrown.expectMessage("Firmware is referencing to non-existent tenant!");
214 firmwareService.saveFirmware(firmware); 283 firmwareService.saveFirmware(firmware);
215 } 284 }
216 285
217 - @Test(expected = DataValidationException.class) 286 + @Test
  287 + public void testSaveFirmwareWithInvalidDeviceProfileId() {
  288 + Firmware firmware = new Firmware();
  289 + firmware.setTenantId(tenantId);
  290 + firmware.setDeviceProfileId(new DeviceProfileId(Uuids.timeBased()));
  291 + firmware.setType(FIRMWARE);
  292 + firmware.setTitle(TITLE);
  293 + firmware.setVersion(VERSION);
  294 + firmware.setFileName(FILE_NAME);
  295 + firmware.setContentType(CONTENT_TYPE);
  296 + firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM);
  297 + firmware.setChecksum(CHECKSUM);
  298 + firmware.setData(DATA);
  299 +
  300 + thrown.expect(DataValidationException.class);
  301 + thrown.expectMessage("Firmware is referencing to non-existent device profile!");
  302 + firmwareService.saveFirmware(firmware);
  303 + }
  304 +
  305 + @Test
218 public void testSaveFirmwareWithEmptyChecksum() { 306 public void testSaveFirmwareWithEmptyChecksum() {
219 Firmware firmware = new Firmware(); 307 Firmware firmware = new Firmware();
220 - firmware.setTenantId(new TenantId(Uuids.timeBased())); 308 + firmware.setTenantId(tenantId);
  309 + firmware.setDeviceProfileId(deviceProfileId);
  310 + firmware.setType(FIRMWARE);
221 firmware.setTitle(TITLE); 311 firmware.setTitle(TITLE);
222 firmware.setVersion(VERSION); 312 firmware.setVersion(VERSION);
223 firmware.setFileName(FILE_NAME); 313 firmware.setFileName(FILE_NAME);
224 firmware.setContentType(CONTENT_TYPE); 314 firmware.setContentType(CONTENT_TYPE);
225 firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM); 315 firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM);
226 firmware.setData(DATA); 316 firmware.setData(DATA);
  317 +
  318 + thrown.expect(DataValidationException.class);
  319 + thrown.expectMessage("Firmware checksum should be specified!");
227 firmwareService.saveFirmware(firmware); 320 firmwareService.saveFirmware(firmware);
228 } 321 }
229 322
230 - @Test(expected = DataValidationException.class) 323 + @Test
231 public void testSaveFirmwareInfoWithExistingTitleAndVersion() { 324 public void testSaveFirmwareInfoWithExistingTitleAndVersion() {
232 FirmwareInfo firmwareInfo = new FirmwareInfo(); 325 FirmwareInfo firmwareInfo = new FirmwareInfo();
233 firmwareInfo.setTenantId(tenantId); 326 firmwareInfo.setTenantId(tenantId);
  327 + firmwareInfo.setDeviceProfileId(deviceProfileId);
  328 + firmwareInfo.setType(FIRMWARE);
234 firmwareInfo.setTitle(TITLE); 329 firmwareInfo.setTitle(TITLE);
235 firmwareInfo.setVersion(VERSION); 330 firmwareInfo.setVersion(VERSION);
236 firmwareService.saveFirmwareInfo(firmwareInfo); 331 firmwareService.saveFirmwareInfo(firmwareInfo);
237 332
238 FirmwareInfo newFirmwareInfo = new FirmwareInfo(); 333 FirmwareInfo newFirmwareInfo = new FirmwareInfo();
239 newFirmwareInfo.setTenantId(tenantId); 334 newFirmwareInfo.setTenantId(tenantId);
  335 + newFirmwareInfo.setDeviceProfileId(deviceProfileId);
  336 + newFirmwareInfo.setType(FIRMWARE);
240 newFirmwareInfo.setTitle(TITLE); 337 newFirmwareInfo.setTitle(TITLE);
241 newFirmwareInfo.setVersion(VERSION); 338 newFirmwareInfo.setVersion(VERSION);
  339 +
  340 + thrown.expect(DataValidationException.class);
  341 + thrown.expectMessage("Firmware with such title and version already exists!");
242 firmwareService.saveFirmwareInfo(newFirmwareInfo); 342 firmwareService.saveFirmwareInfo(newFirmwareInfo);
243 } 343 }
244 344
245 - @Test(expected = DataValidationException.class) 345 + @Test
246 public void testSaveFirmwareWithExistingTitleAndVersion() { 346 public void testSaveFirmwareWithExistingTitleAndVersion() {
247 Firmware firmware = new Firmware(); 347 Firmware firmware = new Firmware();
248 firmware.setTenantId(tenantId); 348 firmware.setTenantId(tenantId);
  349 + firmware.setDeviceProfileId(deviceProfileId);
  350 + firmware.setType(FIRMWARE);
249 firmware.setTitle(TITLE); 351 firmware.setTitle(TITLE);
250 firmware.setVersion(VERSION); 352 firmware.setVersion(VERSION);
251 firmware.setFileName(FILE_NAME); 353 firmware.setFileName(FILE_NAME);
@@ -257,18 +359,27 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -257,18 +359,27 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
257 359
258 Firmware newFirmware = new Firmware(); 360 Firmware newFirmware = new Firmware();
259 newFirmware.setTenantId(tenantId); 361 newFirmware.setTenantId(tenantId);
  362 + newFirmware.setDeviceProfileId(deviceProfileId);
  363 + newFirmware.setType(FIRMWARE);
260 newFirmware.setTitle(TITLE); 364 newFirmware.setTitle(TITLE);
261 newFirmware.setVersion(VERSION); 365 newFirmware.setVersion(VERSION);
262 newFirmware.setFileName(FILE_NAME); 366 newFirmware.setFileName(FILE_NAME);
263 newFirmware.setContentType(CONTENT_TYPE); 367 newFirmware.setContentType(CONTENT_TYPE);
  368 + newFirmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM);
  369 + newFirmware.setChecksum(CHECKSUM);
264 newFirmware.setData(DATA); 370 newFirmware.setData(DATA);
  371 +
  372 + thrown.expect(DataValidationException.class);
  373 + thrown.expectMessage("Firmware with such title and version already exists!");
265 firmwareService.saveFirmware(newFirmware); 374 firmwareService.saveFirmware(newFirmware);
266 } 375 }
267 376
268 - @Test(expected = DataValidationException.class) 377 + @Test
269 public void testDeleteFirmwareWithReferenceByDevice() { 378 public void testDeleteFirmwareWithReferenceByDevice() {
270 Firmware firmware = new Firmware(); 379 Firmware firmware = new Firmware();
271 firmware.setTenantId(tenantId); 380 firmware.setTenantId(tenantId);
  381 + firmware.setDeviceProfileId(deviceProfileId);
  382 + firmware.setType(FIRMWARE);
272 firmware.setTitle(TITLE); 383 firmware.setTitle(TITLE);
273 firmware.setVersion(VERSION); 384 firmware.setVersion(VERSION);
274 firmware.setFileName(FILE_NAME); 385 firmware.setFileName(FILE_NAME);
@@ -281,11 +392,13 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -281,11 +392,13 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
281 Device device = new Device(); 392 Device device = new Device();
282 device.setTenantId(tenantId); 393 device.setTenantId(tenantId);
283 device.setName("My device"); 394 device.setName("My device");
284 - device.setType("default"); 395 + device.setDeviceProfileId(deviceProfileId);
285 device.setFirmwareId(savedFirmware.getId()); 396 device.setFirmwareId(savedFirmware.getId());
286 Device savedDevice = deviceService.saveDevice(device); 397 Device savedDevice = deviceService.saveDevice(device);
287 398
288 try { 399 try {
  400 + thrown.expect(DataValidationException.class);
  401 + thrown.expectMessage("The firmware referenced by the devices cannot be deleted!");
289 firmwareService.deleteFirmware(tenantId, savedFirmware.getId()); 402 firmwareService.deleteFirmware(tenantId, savedFirmware.getId());
290 } finally { 403 } finally {
291 deviceService.deleteDevice(tenantId, savedDevice.getId()); 404 deviceService.deleteDevice(tenantId, savedDevice.getId());
@@ -293,10 +406,12 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -293,10 +406,12 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
293 } 406 }
294 } 407 }
295 408
296 - @Test(expected = DataValidationException.class)  
297 - public void testDeleteFirmwareWithReferenceByDeviceProfile() { 409 + @Test
  410 + public void testUpdateDeviceProfileIdWithReferenceByDevice() {
298 Firmware firmware = new Firmware(); 411 Firmware firmware = new Firmware();
299 firmware.setTenantId(tenantId); 412 firmware.setTenantId(tenantId);
  413 + firmware.setDeviceProfileId(deviceProfileId);
  414 + firmware.setType(FIRMWARE);
300 firmware.setTitle(TITLE); 415 firmware.setTitle(TITLE);
301 firmware.setVersion(VERSION); 416 firmware.setVersion(VERSION);
302 firmware.setFileName(FILE_NAME); 417 firmware.setFileName(FILE_NAME);
@@ -306,12 +421,81 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -306,12 +421,81 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
306 firmware.setData(DATA); 421 firmware.setData(DATA);
307 Firmware savedFirmware = firmwareService.saveFirmware(firmware); 422 Firmware savedFirmware = firmwareService.saveFirmware(firmware);
308 423
309 - DeviceProfile deviceProfile = this.createDeviceProfile(tenantId, "Device Profile");  
310 - deviceProfile.setFirmwareId(savedFirmware.getId()); 424 + Device device = new Device();
  425 + device.setTenantId(tenantId);
  426 + device.setName("My device");
  427 + device.setDeviceProfileId(deviceProfileId);
  428 + device.setFirmwareId(savedFirmware.getId());
  429 + Device savedDevice = deviceService.saveDevice(device);
  430 +
  431 + try {
  432 + thrown.expect(DataValidationException.class);
  433 + thrown.expectMessage("Can`t update deviceProfileId because firmware is already in use!");
  434 + savedFirmware.setDeviceProfileId(null);
  435 + firmwareService.saveFirmware(savedFirmware);
  436 + } finally {
  437 + deviceService.deleteDevice(tenantId, savedDevice.getId());
  438 + firmwareService.deleteFirmware(tenantId, savedFirmware.getId());
  439 + }
  440 + }
  441 +
  442 + @Test
  443 + public void testDeleteFirmwareWithReferenceByDeviceProfile() {
  444 + DeviceProfile deviceProfile = this.createDeviceProfile(tenantId, "Test Device Profile");
311 DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile); 445 DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
312 446
  447 + Firmware firmware = new Firmware();
  448 + firmware.setTenantId(tenantId);
  449 + firmware.setDeviceProfileId(savedDeviceProfile.getId());
  450 + firmware.setType(FIRMWARE);
  451 + firmware.setTitle(TITLE);
  452 + firmware.setVersion(VERSION);
  453 + firmware.setFileName(FILE_NAME);
  454 + firmware.setContentType(CONTENT_TYPE);
  455 + firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM);
  456 + firmware.setChecksum(CHECKSUM);
  457 + firmware.setData(DATA);
  458 + Firmware savedFirmware = firmwareService.saveFirmware(firmware);
  459 +
  460 + savedDeviceProfile.setFirmwareId(savedFirmware.getId());
  461 + deviceProfileService.saveDeviceProfile(savedDeviceProfile);
  462 +
313 try { 463 try {
  464 + thrown.expect(DataValidationException.class);
  465 + thrown.expectMessage("The firmware referenced by the device profile cannot be deleted!");
  466 + firmwareService.deleteFirmware(tenantId, savedFirmware.getId());
  467 + } finally {
  468 + deviceProfileService.deleteDeviceProfile(tenantId, savedDeviceProfile.getId());
314 firmwareService.deleteFirmware(tenantId, savedFirmware.getId()); 469 firmwareService.deleteFirmware(tenantId, savedFirmware.getId());
  470 + }
  471 + }
  472 +
  473 + @Test
  474 + public void testUpdateDeviceProfileIdWithReferenceByDeviceProfile() {
  475 + DeviceProfile deviceProfile = this.createDeviceProfile(tenantId, "Test Device Profile");
  476 + DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
  477 +
  478 + Firmware firmware = new Firmware();
  479 + firmware.setTenantId(tenantId);
  480 + firmware.setDeviceProfileId(savedDeviceProfile.getId());
  481 + firmware.setType(FIRMWARE);
  482 + firmware.setTitle(TITLE);
  483 + firmware.setVersion(VERSION);
  484 + firmware.setFileName(FILE_NAME);
  485 + firmware.setContentType(CONTENT_TYPE);
  486 + firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM);
  487 + firmware.setChecksum(CHECKSUM);
  488 + firmware.setData(DATA);
  489 + Firmware savedFirmware = firmwareService.saveFirmware(firmware);
  490 +
  491 + savedDeviceProfile.setFirmwareId(savedFirmware.getId());
  492 + deviceProfileService.saveDeviceProfile(savedDeviceProfile);
  493 +
  494 + try {
  495 + thrown.expect(DataValidationException.class);
  496 + thrown.expectMessage("Can`t update deviceProfileId because firmware is already in use!");
  497 + savedFirmware.setDeviceProfileId(null);
  498 + firmwareService.saveFirmware(savedFirmware);
315 } finally { 499 } finally {
316 deviceProfileService.deleteDeviceProfile(tenantId, savedDeviceProfile.getId()); 500 deviceProfileService.deleteDeviceProfile(tenantId, savedDeviceProfile.getId());
317 firmwareService.deleteFirmware(tenantId, savedFirmware.getId()); 501 firmwareService.deleteFirmware(tenantId, savedFirmware.getId());
@@ -322,6 +506,8 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -322,6 +506,8 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
322 public void testFindFirmwareById() { 506 public void testFindFirmwareById() {
323 Firmware firmware = new Firmware(); 507 Firmware firmware = new Firmware();
324 firmware.setTenantId(tenantId); 508 firmware.setTenantId(tenantId);
  509 + firmware.setDeviceProfileId(deviceProfileId);
  510 + firmware.setType(FIRMWARE);
325 firmware.setTitle(TITLE); 511 firmware.setTitle(TITLE);
326 firmware.setVersion(VERSION); 512 firmware.setVersion(VERSION);
327 firmware.setFileName(FILE_NAME); 513 firmware.setFileName(FILE_NAME);
@@ -341,6 +527,8 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -341,6 +527,8 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
341 public void testFindFirmwareInfoById() { 527 public void testFindFirmwareInfoById() {
342 FirmwareInfo firmware = new FirmwareInfo(); 528 FirmwareInfo firmware = new FirmwareInfo();
343 firmware.setTenantId(tenantId); 529 firmware.setTenantId(tenantId);
  530 + firmware.setDeviceProfileId(deviceProfileId);
  531 + firmware.setType(FIRMWARE);
344 firmware.setTitle(TITLE); 532 firmware.setTitle(TITLE);
345 firmware.setVersion(VERSION); 533 firmware.setVersion(VERSION);
346 FirmwareInfo savedFirmware = firmwareService.saveFirmwareInfo(firmware); 534 FirmwareInfo savedFirmware = firmwareService.saveFirmwareInfo(firmware);
@@ -355,6 +543,8 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -355,6 +543,8 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
355 public void testDeleteFirmware() { 543 public void testDeleteFirmware() {
356 Firmware firmware = new Firmware(); 544 Firmware firmware = new Firmware();
357 firmware.setTenantId(tenantId); 545 firmware.setTenantId(tenantId);
  546 + firmware.setDeviceProfileId(deviceProfileId);
  547 + firmware.setType(FIRMWARE);
358 firmware.setTitle(TITLE); 548 firmware.setTitle(TITLE);
359 firmware.setVersion(VERSION); 549 firmware.setVersion(VERSION);
360 firmware.setFileName(FILE_NAME); 550 firmware.setFileName(FILE_NAME);
@@ -377,6 +567,8 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -377,6 +567,8 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
377 for (int i = 0; i < 165; i++) { 567 for (int i = 0; i < 165; i++) {
378 Firmware firmware = new Firmware(); 568 Firmware firmware = new Firmware();
379 firmware.setTenantId(tenantId); 569 firmware.setTenantId(tenantId);
  570 + firmware.setDeviceProfileId(deviceProfileId);
  571 + firmware.setType(FIRMWARE);
380 firmware.setTitle(TITLE); 572 firmware.setTitle(TITLE);
381 firmware.setVersion(VERSION + i); 573 firmware.setVersion(VERSION + i);
382 firmware.setFileName(FILE_NAME); 574 firmware.setFileName(FILE_NAME);
@@ -420,6 +612,8 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -420,6 +612,8 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
420 for (int i = 0; i < 165; i++) { 612 for (int i = 0; i < 165; i++) {
421 FirmwareInfo firmwareInfo = new FirmwareInfo(); 613 FirmwareInfo firmwareInfo = new FirmwareInfo();
422 firmwareInfo.setTenantId(tenantId); 614 firmwareInfo.setTenantId(tenantId);
  615 + firmwareInfo.setDeviceProfileId(deviceProfileId);
  616 + firmwareInfo.setType(FIRMWARE);
423 firmwareInfo.setTitle(TITLE); 617 firmwareInfo.setTitle(TITLE);
424 firmwareInfo.setVersion(VERSION + i); 618 firmwareInfo.setVersion(VERSION + i);
425 firmwareInfo.setFileName(FILE_NAME); 619 firmwareInfo.setFileName(FILE_NAME);
@@ -434,7 +628,7 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -434,7 +628,7 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
434 PageLink pageLink = new PageLink(16); 628 PageLink pageLink = new PageLink(16);
435 PageData<FirmwareInfo> pageData; 629 PageData<FirmwareInfo> pageData;
436 do { 630 do {
437 - pageData = firmwareService.findTenantFirmwaresByTenantIdAndHasData(tenantId, false, pageLink); 631 + pageData = firmwareService.findTenantFirmwaresByTenantIdAndDeviceProfileIdAndTypeAndHasData(tenantId, deviceProfileId, FIRMWARE, false, pageLink);
438 loadedFirmwares.addAll(pageData.getData()); 632 loadedFirmwares.addAll(pageData.getData());
439 if (pageData.hasNext()) { 633 if (pageData.hasNext()) {
440 pageLink = pageLink.nextPageLink(); 634 pageLink = pageLink.nextPageLink();
@@ -450,6 +644,8 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -450,6 +644,8 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
450 Firmware firmware = new Firmware(f.getId()); 644 Firmware firmware = new Firmware(f.getId());
451 firmware.setCreatedTime(f.getCreatedTime()); 645 firmware.setCreatedTime(f.getCreatedTime());
452 firmware.setTenantId(f.getTenantId()); 646 firmware.setTenantId(f.getTenantId());
  647 + firmware.setDeviceProfileId(deviceProfileId);
  648 + firmware.setType(FIRMWARE);
453 firmware.setTitle(f.getTitle()); 649 firmware.setTitle(f.getTitle());
454 firmware.setVersion(f.getVersion()); 650 firmware.setVersion(f.getVersion());
455 firmware.setFileName(FILE_NAME); 651 firmware.setFileName(FILE_NAME);
@@ -465,7 +661,7 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -465,7 +661,7 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
465 loadedFirmwares = new ArrayList<>(); 661 loadedFirmwares = new ArrayList<>();
466 pageLink = new PageLink(16); 662 pageLink = new PageLink(16);
467 do { 663 do {
468 - pageData = firmwareService.findTenantFirmwaresByTenantIdAndHasData(tenantId, true, pageLink); 664 + pageData = firmwareService.findTenantFirmwaresByTenantIdAndDeviceProfileIdAndTypeAndHasData(tenantId, deviceProfileId, FIRMWARE, true, pageLink);
469 loadedFirmwares.addAll(pageData.getData()); 665 loadedFirmwares.addAll(pageData.getData());
470 if (pageData.hasNext()) { 666 if (pageData.hasNext()) {
471 pageLink = pageLink.nextPageLink(); 667 pageLink = pageLink.nextPageLink();
@@ -361,7 +361,7 @@ export class EntityService { @@ -361,7 +361,7 @@ export class EntityService {
361 break; 361 break;
362 case EntityType.FIRMWARE: 362 case EntityType.FIRMWARE:
363 pageLink.sortOrder.property = 'title'; 363 pageLink.sortOrder.property = 'title';
364 - entitiesObservable = this.firmwareService.getFirmwares(pageLink, true, config); 364 + entitiesObservable = this.firmwareService.getFirmwares(pageLink, config);
365 break; 365 break;
366 } 366 }
367 return entitiesObservable; 367 return entitiesObservable;
@@ -20,7 +20,7 @@ import { PageLink } from '@shared/models/page/page-link'; @@ -20,7 +20,7 @@ import { PageLink } from '@shared/models/page/page-link';
20 import { defaultHttpOptionsFromConfig, defaultHttpUploadOptions, RequestConfig } from '@core/http/http-utils'; 20 import { defaultHttpOptionsFromConfig, defaultHttpUploadOptions, RequestConfig } from '@core/http/http-utils';
21 import { Observable } from 'rxjs'; 21 import { Observable } from 'rxjs';
22 import { PageData } from '@shared/models/page/page-data'; 22 import { PageData } from '@shared/models/page/page-data';
23 -import { Firmware, FirmwareInfo } from '@shared/models/firmware.models'; 23 +import { Firmware, FirmwareInfo, FirmwareType } from '@shared/models/firmware.models';
24 import { catchError, map, mergeMap } from 'rxjs/operators'; 24 import { catchError, map, mergeMap } from 'rxjs/operators';
25 import { deepClone, isDefinedAndNotNull } from '@core/utils'; 25 import { deepClone, isDefinedAndNotNull } from '@core/utils';
26 26
@@ -34,12 +34,13 @@ export class FirmwareService { @@ -34,12 +34,13 @@ export class FirmwareService {
34 34
35 } 35 }
36 36
37 - public getFirmwares(pageLink: PageLink, hasData?: boolean, config?: RequestConfig): Observable<PageData<FirmwareInfo>> {  
38 - let url = `/api/firmwares`;  
39 - if (isDefinedAndNotNull(hasData)) {  
40 - url += `/${hasData}`;  
41 - }  
42 - url += `${pageLink.toQuery()}`; 37 + public getFirmwares(pageLink: PageLink, config?: RequestConfig): Observable<PageData<FirmwareInfo>> {
  38 + return this.http.get<PageData<FirmwareInfo>>(`/api/firmwares${pageLink.toQuery()}`, defaultHttpOptionsFromConfig(config));
  39 + }
  40 +
  41 + public getFirmwaresInfoByDeviceProfileId(pageLink: PageLink, deviceProfileId: string, type: FirmwareType,
  42 + hasData = true, config?: RequestConfig): Observable<PageData<FirmwareInfo>> {
  43 + const url = `/api/firmwares/${deviceProfileId}/${type}/${hasData}${pageLink.toQuery()}`;
43 return this.http.get<PageData<FirmwareInfo>>(url, defaultHttpOptionsFromConfig(config)); 44 return this.http.get<PageData<FirmwareInfo>>(url, defaultHttpOptionsFromConfig(config));
44 } 45 }
45 46
@@ -60,10 +60,6 @@ @@ -60,10 +60,6 @@
60 {{ 'device-profile.type-required' | translate }} 60 {{ 'device-profile.type-required' | translate }}
61 </mat-error> 61 </mat-error>
62 </mat-form-field> 62 </mat-form-field>
63 - <tb-firmware-autocomplete  
64 - [useFullEntityId]="true"  
65 - formControlName="firmwareId">  
66 - </tb-firmware-autocomplete>  
67 <mat-form-field class="mat-block"> 63 <mat-form-field class="mat-block">
68 <mat-label translate>device-profile.description</mat-label> 64 <mat-label translate>device-profile.description</mat-label>
69 <textarea matInput formControlName="description" rows="2"></textarea> 65 <textarea matInput formControlName="description" rows="2"></textarea>
@@ -108,7 +108,6 @@ export class AddDeviceProfileDialogComponent extends @@ -108,7 +108,6 @@ export class AddDeviceProfileDialogComponent extends
108 type: [DeviceProfileType.DEFAULT, [Validators.required]], 108 type: [DeviceProfileType.DEFAULT, [Validators.required]],
109 defaultRuleChainId: [null, []], 109 defaultRuleChainId: [null, []],
110 defaultQueueName: ['', []], 110 defaultQueueName: ['', []],
111 - firmwareId: [null],  
112 description: ['', []] 111 description: ['', []]
113 } 112 }
114 ); 113 );
@@ -187,7 +186,6 @@ export class AddDeviceProfileDialogComponent extends @@ -187,7 +186,6 @@ export class AddDeviceProfileDialogComponent extends
187 transportType: this.transportConfigFormGroup.get('transportType').value, 186 transportType: this.transportConfigFormGroup.get('transportType').value,
188 provisionType: deviceProvisionConfiguration.type, 187 provisionType: deviceProvisionConfiguration.type,
189 provisionDeviceKey, 188 provisionDeviceKey,
190 - firmwareId: this.deviceProfileDetailsFormGroup.get('firmwareId').value,  
191 description: this.deviceProfileDetailsFormGroup.get('description').value, 189 description: this.deviceProfileDetailsFormGroup.get('description').value,
192 profileData: { 190 profileData: {
193 configuration: createDeviceProfileConfiguration(DeviceProfileType.DEFAULT), 191 configuration: createDeviceProfileConfiguration(DeviceProfileType.DEFAULT),
@@ -65,8 +65,16 @@ @@ -65,8 +65,16 @@
65 </tb-queue-type-list> 65 </tb-queue-type-list>
66 <tb-firmware-autocomplete 66 <tb-firmware-autocomplete
67 [useFullEntityId]="true" 67 [useFullEntityId]="true"
  68 + [type]="firmwareTypes.FIRMWARE"
  69 + [deviceProfileId]="deviceProfileId?.id"
68 formControlName="firmwareId"> 70 formControlName="firmwareId">
69 </tb-firmware-autocomplete> 71 </tb-firmware-autocomplete>
  72 + <tb-firmware-autocomplete
  73 + [useFullEntityId]="true"
  74 + [type]="firmwareTypes.SOFTWARE"
  75 + [deviceProfileId]="deviceProfileId?.id"
  76 + formControlName="softwareId">
  77 + </tb-firmware-autocomplete>
70 <mat-form-field fxHide class="mat-block"> 78 <mat-form-field fxHide class="mat-block">
71 <mat-label translate>device-profile.type</mat-label> 79 <mat-label translate>device-profile.type</mat-label>
72 <mat-select formControlName="type" required> 80 <mat-select formControlName="type" required>
@@ -40,6 +40,7 @@ import { EntityType } from '@shared/models/entity-type.models'; @@ -40,6 +40,7 @@ import { EntityType } from '@shared/models/entity-type.models';
40 import { RuleChainId } from '@shared/models/id/rule-chain-id'; 40 import { RuleChainId } from '@shared/models/id/rule-chain-id';
41 import { ServiceType } from '@shared/models/queue.models'; 41 import { ServiceType } from '@shared/models/queue.models';
42 import { EntityId } from '@shared/models/id/entity-id'; 42 import { EntityId } from '@shared/models/id/entity-id';
  43 +import { FirmwareType } from '@shared/models/firmware.models';
43 44
44 @Component({ 45 @Component({
45 selector: 'tb-device-profile', 46 selector: 'tb-device-profile',
@@ -69,6 +70,8 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> { @@ -69,6 +70,8 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> {
69 70
70 deviceProfileId: EntityId; 71 deviceProfileId: EntityId;
71 72
  73 + firmwareTypes = FirmwareType;
  74 +
72 constructor(protected store: Store<AppState>, 75 constructor(protected store: Store<AppState>,
73 protected translate: TranslateService, 76 protected translate: TranslateService,
74 @Optional() @Inject('entity') protected entityValue: DeviceProfile, 77 @Optional() @Inject('entity') protected entityValue: DeviceProfile,
@@ -110,6 +113,7 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> { @@ -110,6 +113,7 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> {
110 defaultRuleChainId: [entity && entity.defaultRuleChainId ? entity.defaultRuleChainId.id : null, []], 113 defaultRuleChainId: [entity && entity.defaultRuleChainId ? entity.defaultRuleChainId.id : null, []],
111 defaultQueueName: [entity ? entity.defaultQueueName : '', []], 114 defaultQueueName: [entity ? entity.defaultQueueName : '', []],
112 firmwareId: [entity ? entity.firmwareId : null], 115 firmwareId: [entity ? entity.firmwareId : null],
  116 + softwareId: [entity ? entity.softwareId : null],
113 description: [entity ? entity.description : '', []], 117 description: [entity ? entity.description : '', []],
114 } 118 }
115 ); 119 );
@@ -186,6 +190,7 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> { @@ -186,6 +190,7 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> {
186 this.entityForm.patchValue({defaultRuleChainId: entity.defaultRuleChainId ? entity.defaultRuleChainId.id : null}, {emitEvent: false}); 190 this.entityForm.patchValue({defaultRuleChainId: entity.defaultRuleChainId ? entity.defaultRuleChainId.id : null}, {emitEvent: false});
187 this.entityForm.patchValue({defaultQueueName: entity.defaultQueueName}, {emitEvent: false}); 191 this.entityForm.patchValue({defaultQueueName: entity.defaultQueueName}, {emitEvent: false});
188 this.entityForm.patchValue({firmwareId: entity.firmwareId}, {emitEvent: false}); 192 this.entityForm.patchValue({firmwareId: entity.firmwareId}, {emitEvent: false});
  193 + this.entityForm.patchValue({softwareId: entity.softwareId}, {emitEvent: false});
189 this.entityForm.patchValue({description: entity.description}, {emitEvent: false}); 194 this.entityForm.patchValue({description: entity.description}, {emitEvent: false});
190 } 195 }
191 196
@@ -48,10 +48,6 @@ @@ -48,10 +48,6 @@
48 <mat-label translate>device.label</mat-label> 48 <mat-label translate>device.label</mat-label>
49 <input matInput formControlName="label"> 49 <input matInput formControlName="label">
50 </mat-form-field> 50 </mat-form-field>
51 - <tb-firmware-autocomplete  
52 - [useFullEntityId]="true"  
53 - formControlName="firmwareId">  
54 - </tb-firmware-autocomplete>  
55 <mat-form-field class="mat-block" style="padding-bottom: 14px;"> 51 <mat-form-field class="mat-block" style="padding-bottom: 14px;">
56 <mat-label translate>device-profile.transport-type</mat-label> 52 <mat-label translate>device-profile.transport-type</mat-label>
57 <mat-select formControlName="transportType" required> 53 <mat-select formControlName="transportType" required>
@@ -107,7 +107,6 @@ export class DeviceWizardDialogComponent extends @@ -107,7 +107,6 @@ export class DeviceWizardDialogComponent extends
107 this.deviceWizardFormGroup = this.fb.group({ 107 this.deviceWizardFormGroup = this.fb.group({
108 name: ['', Validators.required], 108 name: ['', Validators.required],
109 label: [''], 109 label: [''],
110 - firmwareId: [null],  
111 gateway: [false], 110 gateway: [false],
112 overwriteActivityTime: [false], 111 overwriteActivityTime: [false],
113 transportType: [DeviceTransportType.DEFAULT, Validators.required], 112 transportType: [DeviceTransportType.DEFAULT, Validators.required],
@@ -313,7 +312,6 @@ export class DeviceWizardDialogComponent extends @@ -313,7 +312,6 @@ export class DeviceWizardDialogComponent extends
313 const device = { 312 const device = {
314 name: this.deviceWizardFormGroup.get('name').value, 313 name: this.deviceWizardFormGroup.get('name').value,
315 label: this.deviceWizardFormGroup.get('label').value, 314 label: this.deviceWizardFormGroup.get('label').value,
316 - firmwareId: this.deviceWizardFormGroup.get('firmwareId').value,  
317 deviceProfileId: profileId, 315 deviceProfileId: profileId,
318 additionalInfo: { 316 additionalInfo: {
319 gateway: this.deviceWizardFormGroup.get('gateway').value, 317 gateway: this.deviceWizardFormGroup.get('gateway').value,
@@ -103,8 +103,16 @@ @@ -103,8 +103,16 @@
103 </mat-form-field> 103 </mat-form-field>
104 <tb-firmware-autocomplete 104 <tb-firmware-autocomplete
105 [useFullEntityId]="true" 105 [useFullEntityId]="true"
  106 + [type]="firmwareTypes.FIRMWARE"
  107 + [deviceProfileId]="entityForm.get('deviceProfileId').value?.id"
106 formControlName="firmwareId"> 108 formControlName="firmwareId">
107 </tb-firmware-autocomplete> 109 </tb-firmware-autocomplete>
  110 + <tb-firmware-autocomplete
  111 + [useFullEntityId]="true"
  112 + [type]="firmwareTypes.SOFTWARE"
  113 + [deviceProfileId]="entityForm.get('deviceProfileId').value?.id"
  114 + formControlName="softwareId">
  115 + </tb-firmware-autocomplete>
108 <tb-device-data 116 <tb-device-data
109 formControlName="deviceData" 117 formControlName="deviceData"
110 required> 118 required>
@@ -34,6 +34,7 @@ import { ActionNotificationShow } from '@core/notification/notification.actions' @@ -34,6 +34,7 @@ import { ActionNotificationShow } from '@core/notification/notification.actions'
34 import { TranslateService } from '@ngx-translate/core'; 34 import { TranslateService } from '@ngx-translate/core';
35 import { EntityTableConfig } from '@home/models/entity/entities-table-config.models'; 35 import { EntityTableConfig } from '@home/models/entity/entities-table-config.models';
36 import { Subject } from 'rxjs'; 36 import { Subject } from 'rxjs';
  37 +import { FirmwareType } from '@shared/models/firmware.models';
37 38
38 @Component({ 39 @Component({
39 selector: 'tb-device', 40 selector: 'tb-device',
@@ -48,6 +49,8 @@ export class DeviceComponent extends EntityComponent<DeviceInfo> { @@ -48,6 +49,8 @@ export class DeviceComponent extends EntityComponent<DeviceInfo> {
48 49
49 deviceScope: 'tenant' | 'customer' | 'customer_user' | 'edge'; 50 deviceScope: 'tenant' | 'customer' | 'customer_user' | 'edge';
50 51
  52 + firmwareTypes = FirmwareType;
  53 +
51 constructor(protected store: Store<AppState>, 54 constructor(protected store: Store<AppState>,
52 protected translate: TranslateService, 55 protected translate: TranslateService,
53 @Inject('entity') protected entityValue: DeviceInfo, 56 @Inject('entity') protected entityValue: DeviceInfo,
@@ -80,6 +83,7 @@ export class DeviceComponent extends EntityComponent<DeviceInfo> { @@ -80,6 +83,7 @@ export class DeviceComponent extends EntityComponent<DeviceInfo> {
80 name: [entity ? entity.name : '', [Validators.required]], 83 name: [entity ? entity.name : '', [Validators.required]],
81 deviceProfileId: [entity ? entity.deviceProfileId : null, [Validators.required]], 84 deviceProfileId: [entity ? entity.deviceProfileId : null, [Validators.required]],
82 firmwareId: [entity ? entity.firmwareId : null], 85 firmwareId: [entity ? entity.firmwareId : null],
  86 + softwareId: [entity ? entity.softwareId : null],
83 label: [entity ? entity.label : ''], 87 label: [entity ? entity.label : ''],
84 deviceData: [entity ? entity.deviceData : null, [Validators.required]], 88 deviceData: [entity ? entity.deviceData : null, [Validators.required]],
85 additionalInfo: this.fb.group( 89 additionalInfo: this.fb.group(
@@ -94,19 +98,19 @@ export class DeviceComponent extends EntityComponent<DeviceInfo> { @@ -94,19 +98,19 @@ export class DeviceComponent extends EntityComponent<DeviceInfo> {
94 } 98 }
95 99
96 updateForm(entity: DeviceInfo) { 100 updateForm(entity: DeviceInfo) {
97 - this.entityForm.patchValue({name: entity.name});  
98 - this.entityForm.patchValue({deviceProfileId: entity.deviceProfileId});  
99 - this.entityForm.patchValue({firmwareId: entity.firmwareId});  
100 - this.entityForm.patchValue({label: entity.label});  
101 - this.entityForm.patchValue({deviceData: entity.deviceData});  
102 this.entityForm.patchValue({ 101 this.entityForm.patchValue({
103 - additionalInfo:  
104 - {  
105 - gateway: entity.additionalInfo ? entity.additionalInfo.gateway : false,  
106 - overwriteActivityTime: entity.additionalInfo ? entity.additionalInfo.overwriteActivityTime : false  
107 - } 102 + name: entity.name,
  103 + deviceProfileId: entity.deviceProfileId,
  104 + firmwareId: entity.firmwareId,
  105 + softwareId: entity.softwareId,
  106 + label: entity.label,
  107 + deviceData: entity.deviceData,
  108 + additionalInfo: {
  109 + gateway: entity.additionalInfo ? entity.additionalInfo.gateway : false,
  110 + overwriteActivityTime: entity.additionalInfo ? entity.additionalInfo.overwriteActivityTime : false,
  111 + description: entity.additionalInfo ? entity.additionalInfo.description : ''
  112 + }
108 }); 113 });
109 - this.entityForm.patchValue({additionalInfo: {description: entity.additionalInfo ? entity.additionalInfo.description : ''}});  
110 } 114 }
111 115
112 116
@@ -152,6 +156,10 @@ export class DeviceComponent extends EntityComponent<DeviceInfo> { @@ -152,6 +156,10 @@ export class DeviceComponent extends EntityComponent<DeviceInfo> {
152 this.entityForm.markAsDirty(); 156 this.entityForm.markAsDirty();
153 } 157 }
154 } 158 }
  159 + this.entityForm.patchValue({
  160 + firmwareId: null,
  161 + softwareId: null
  162 + });
155 } 163 }
156 } 164 }
157 } 165 }
@@ -21,7 +21,12 @@ import { @@ -21,7 +21,12 @@ import {
21 EntityTableColumn, 21 EntityTableColumn,
22 EntityTableConfig 22 EntityTableConfig
23 } from '@home/models/entity/entities-table-config.models'; 23 } from '@home/models/entity/entities-table-config.models';
24 -import { Firmware, FirmwareInfo } from '@shared/models/firmware.models'; 24 +import {
  25 + ChecksumAlgorithmTranslationMap,
  26 + Firmware,
  27 + FirmwareInfo,
  28 + FirmwareTypeTranslationMap
  29 +} from '@shared/models/firmware.models';
25 import { EntityType, entityTypeResources, entityTypeTranslations } from '@shared/models/entity-type.models'; 30 import { EntityType, entityTypeResources, entityTypeTranslations } from '@shared/models/entity-type.models';
26 import { TranslateService } from '@ngx-translate/core'; 31 import { TranslateService } from '@ngx-translate/core';
27 import { DatePipe } from '@angular/common'; 32 import { DatePipe } from '@angular/common';
@@ -49,14 +54,17 @@ export class FirmwareTableConfigResolve implements Resolve<EntityTableConfig<Fir @@ -49,14 +54,17 @@ export class FirmwareTableConfigResolve implements Resolve<EntityTableConfig<Fir
49 54
50 this.config.columns.push( 55 this.config.columns.push(
51 new DateEntityTableColumn<FirmwareInfo>('createdTime', 'common.created-time', this.datePipe, '150px'), 56 new DateEntityTableColumn<FirmwareInfo>('createdTime', 'common.created-time', this.datePipe, '150px'),
52 - new EntityTableColumn<FirmwareInfo>('title', 'firmware.title', '33%'),  
53 - new EntityTableColumn<FirmwareInfo>('version', 'firmware.version', '33%'),  
54 - new EntityTableColumn<FirmwareInfo>('fileName', 'firmware.file-name', '33%'), 57 + new EntityTableColumn<FirmwareInfo>('title', 'firmware.title', '25%'),
  58 + new EntityTableColumn<FirmwareInfo>('version', 'firmware.version', '25%'),
  59 + new EntityTableColumn<FirmwareInfo>('type', 'firmware.type', '25%', entity => {
  60 + return this.translate.instant(FirmwareTypeTranslationMap.get(entity.type));
  61 + }),
  62 + new EntityTableColumn<FirmwareInfo>('fileName', 'firmware.file-name', '25%'),
55 new EntityTableColumn<FirmwareInfo>('dataSize', 'firmware.file-size', '70px', entity => { 63 new EntityTableColumn<FirmwareInfo>('dataSize', 'firmware.file-size', '70px', entity => {
56 return this.fileSize.transform(entity.dataSize || 0); 64 return this.fileSize.transform(entity.dataSize || 0);
57 }), 65 }),
58 new EntityTableColumn<FirmwareInfo>('checksum', 'firmware.checksum', '540px', entity => { 66 new EntityTableColumn<FirmwareInfo>('checksum', 'firmware.checksum', '540px', entity => {
59 - return `${entity.checksumAlgorithm}: ${entity.checksum}`; 67 + return `${ChecksumAlgorithmTranslationMap.get(entity.checksumAlgorithm)}: ${entity.checksum}`;
60 }, () => ({}), false) 68 }, () => ({}), false)
61 ); 69 );
62 70
@@ -67,10 +67,27 @@ @@ -67,10 +67,27 @@
67 </mat-error> 67 </mat-error>
68 </mat-form-field> 68 </mat-form-field>
69 </div> 69 </div>
  70 + <div fxLayout="row" fxLayoutGap.gt-xs="8px" fxLayout.xs="column">
  71 + <mat-form-field fxFlex="45">
  72 + <mat-label translate>firmware.type</mat-label>
  73 + <input *ngIf="!isAdd" matInput type="text" [readonly]="isEdit" [disabled]="!isEdit"
  74 + value="{{ firmwareTypeTranslationMap.get(entityForm.get('type').value) | translate }}">
  75 + <mat-select formControlName="type" required *ngIf="isAdd">
  76 + <mat-option *ngFor="let firmwareType of firmwareTypes" [value]="firmwareType">
  77 + {{ firmwareTypeTranslationMap.get(firmwareType) | translate }}
  78 + </mat-option>
  79 + </mat-select>
  80 + </mat-form-field>
  81 + <tb-device-profile-autocomplete
  82 + formControlName="deviceProfileId" fxFlex
  83 + [editProfileEnabled]="false">
  84 + </tb-device-profile-autocomplete>
  85 + </div>
70 <div fxLayout="row" fxLayoutGap.gt-xs="8px" fxLayoutGap.sm="8px" fxLayout.xs="column" fxLayout.md="column"> 86 <div fxLayout="row" fxLayoutGap.gt-xs="8px" fxLayoutGap.sm="8px" fxLayout.xs="column" fxLayout.md="column">
71 <mat-form-field class="mat-block" fxFlex="33"> 87 <mat-form-field class="mat-block" fxFlex="33">
72 <mat-label translate>firmware.checksum-algorithm</mat-label> 88 <mat-label translate>firmware.checksum-algorithm</mat-label>
73 - <input *ngIf="!isAdd" matInput formControlName="checksumAlgorithm" type="text" [readonly]="isEdit"> 89 + <input *ngIf="!isAdd" matInput type="text" [readonly]="isEdit" [disabled]="!isEdit"
  90 + value="{{ checksumAlgorithmTranslationMap.get(entityForm.get('checksumAlgorithm').value) | translate }}">
74 <mat-select formControlName="checksumAlgorithm" *ngIf="isAdd"> 91 <mat-select formControlName="checksumAlgorithm" *ngIf="isAdd">
75 <mat-option [value]=null></mat-option> 92 <mat-option [value]=null></mat-option>
76 <mat-option *ngFor="let checksumAlgorithm of checksumAlgorithms" [value]="checksumAlgorithm"> 93 <mat-option *ngFor="let checksumAlgorithm of checksumAlgorithms" [value]="checksumAlgorithm">
@@ -22,7 +22,13 @@ import { TranslateService } from '@ngx-translate/core'; @@ -22,7 +22,13 @@ import { TranslateService } from '@ngx-translate/core';
22 import { EntityTableConfig } from '@home/models/entity/entities-table-config.models'; 22 import { EntityTableConfig } from '@home/models/entity/entities-table-config.models';
23 import { FormBuilder, FormGroup, Validators } from '@angular/forms'; 23 import { FormBuilder, FormGroup, Validators } from '@angular/forms';
24 import { EntityComponent } from '@home/components/entity/entity.component'; 24 import { EntityComponent } from '@home/components/entity/entity.component';
25 -import { ChecksumAlgorithm, ChecksumAlgorithmTranslationMap, Firmware } from '@shared/models/firmware.models'; 25 +import {
  26 + ChecksumAlgorithm,
  27 + ChecksumAlgorithmTranslationMap,
  28 + Firmware,
  29 + FirmwareType,
  30 + FirmwareTypeTranslationMap
  31 +} from '@shared/models/firmware.models';
26 import { distinctUntilChanged, map, takeUntil } from 'rxjs/operators'; 32 import { distinctUntilChanged, map, takeUntil } from 'rxjs/operators';
27 import { ActionNotificationShow } from '@core/notification/notification.actions'; 33 import { ActionNotificationShow } from '@core/notification/notification.actions';
28 34
@@ -36,6 +42,8 @@ export class FirmwaresComponent extends EntityComponent<Firmware> implements OnI @@ -36,6 +42,8 @@ export class FirmwaresComponent extends EntityComponent<Firmware> implements OnI
36 42
37 checksumAlgorithms = Object.values(ChecksumAlgorithm); 43 checksumAlgorithms = Object.values(ChecksumAlgorithm);
38 checksumAlgorithmTranslationMap = ChecksumAlgorithmTranslationMap; 44 checksumAlgorithmTranslationMap = ChecksumAlgorithmTranslationMap;
  45 + firmwareTypes = Object.values(FirmwareType);
  46 + firmwareTypeTranslationMap = FirmwareTypeTranslationMap;
39 47
40 constructor(protected store: Store<AppState>, 48 constructor(protected store: Store<AppState>,
41 protected translate: TranslateService, 49 protected translate: TranslateService,
@@ -83,6 +91,8 @@ export class FirmwaresComponent extends EntityComponent<Firmware> implements OnI @@ -83,6 +91,8 @@ export class FirmwaresComponent extends EntityComponent<Firmware> implements OnI
83 const form = this.fb.group({ 91 const form = this.fb.group({
84 title: [entity ? entity.title : '', [Validators.required, Validators.maxLength(255)]], 92 title: [entity ? entity.title : '', [Validators.required, Validators.maxLength(255)]],
85 version: [entity ? entity.version : '', [Validators.required, Validators.maxLength(255)]], 93 version: [entity ? entity.version : '', [Validators.required, Validators.maxLength(255)]],
  94 + type: [entity?.type ? entity.type : FirmwareType.FIRMWARE, [Validators.required]],
  95 + deviceProfileId: [entity ? entity.deviceProfileId : null],
86 checksumAlgorithm: [entity ? entity.checksumAlgorithm : null], 96 checksumAlgorithm: [entity ? entity.checksumAlgorithm : null],
87 checksum: [entity ? entity.checksum : '', Validators.maxLength(1020)], 97 checksum: [entity ? entity.checksum : '', Validators.maxLength(1020)],
88 additionalInfo: this.fb.group( 98 additionalInfo: this.fb.group(
@@ -105,6 +115,8 @@ export class FirmwaresComponent extends EntityComponent<Firmware> implements OnI @@ -105,6 +115,8 @@ export class FirmwaresComponent extends EntityComponent<Firmware> implements OnI
105 this.entityForm.patchValue({ 115 this.entityForm.patchValue({
106 title: entity.title, 116 title: entity.title,
107 version: entity.version, 117 version: entity.version,
  118 + type: entity.type,
  119 + deviceProfileId: entity.deviceProfileId,
108 checksumAlgorithm: entity.checksumAlgorithm, 120 checksumAlgorithm: entity.checksumAlgorithm,
109 checksum: entity.checksum, 121 checksum: entity.checksum,
110 fileName: entity.fileName, 122 fileName: entity.fileName,
@@ -37,11 +37,11 @@ @@ -37,11 +37,11 @@
37 <mat-option *ngIf="!(filteredFirmwares | async)?.length" [value]="null" class="tb-not-found"> 37 <mat-option *ngIf="!(filteredFirmwares | async)?.length" [value]="null" class="tb-not-found">
38 <div class="tb-not-found-content" (click)="$event.stopPropagation()"> 38 <div class="tb-not-found-content" (click)="$event.stopPropagation()">
39 <div *ngIf="!textIsNotEmpty(searchText); else searchNotEmpty"> 39 <div *ngIf="!textIsNotEmpty(searchText); else searchNotEmpty">
40 - <span translate>firmware.no-firmware-text</span> 40 + <span>{{ notFoundFirmware | translate }}</span>
41 </div> 41 </div>
42 <ng-template #searchNotEmpty> 42 <ng-template #searchNotEmpty>
43 <span> 43 <span>
44 - {{ translate.get('firmware.no-firmware-matching', 44 + {{ translate.get(notMatchingFirmware,
45 {entity: truncate.transform(searchText, true, 6, &apos;...&apos;)}) | async }} 45 {entity: truncate.transform(searchText, true, 6, &apos;...&apos;)}) | async }}
46 </span> 46 </span>
47 </ng-template> 47 </ng-template>
@@ -28,7 +28,7 @@ import { BaseData } from '@shared/models/base-data'; @@ -28,7 +28,7 @@ import { BaseData } from '@shared/models/base-data';
28 import { EntityService } from '@core/http/entity.service'; 28 import { EntityService } from '@core/http/entity.service';
29 import { TruncatePipe } from '@shared/pipe/truncate.pipe'; 29 import { TruncatePipe } from '@shared/pipe/truncate.pipe';
30 import { MatAutocompleteTrigger } from '@angular/material/autocomplete'; 30 import { MatAutocompleteTrigger } from '@angular/material/autocomplete';
31 -import { FirmwareInfo } from '@shared/models/firmware.models'; 31 +import { FirmwareInfo, FirmwareType } from '@shared/models/firmware.models';
32 import { FirmwareService } from '@core/http/firmware.service'; 32 import { FirmwareService } from '@core/http/firmware.service';
33 import { PageLink } from '@shared/models/page/page-link'; 33 import { PageLink } from '@shared/models/page/page-link';
34 import { Direction } from '@shared/models/page/sort-order'; 34 import { Direction } from '@shared/models/page/sort-order';
@@ -50,6 +50,12 @@ export class FirmwareAutocompleteComponent implements ControlValueAccessor, OnIn @@ -50,6 +50,12 @@ export class FirmwareAutocompleteComponent implements ControlValueAccessor, OnIn
50 modelValue: string | null; 50 modelValue: string | null;
51 51
52 @Input() 52 @Input()
  53 + type = FirmwareType.FIRMWARE;
  54 +
  55 + @Input()
  56 + deviceProfileId: string;
  57 +
  58 + @Input()
53 labelText: string; 59 labelText: string;
54 60
55 @Input() 61 @Input()
@@ -81,6 +87,23 @@ export class FirmwareAutocompleteComponent implements ControlValueAccessor, OnIn @@ -81,6 +87,23 @@ export class FirmwareAutocompleteComponent implements ControlValueAccessor, OnIn
81 87
82 private dirty = false; 88 private dirty = false;
83 89
  90 + private firmwareTypeTranslation = new Map<FirmwareType, any>(
  91 + [
  92 + [FirmwareType.FIRMWARE, {
  93 + label: 'firmware.firmware',
  94 + required: 'firmware.firmware-required',
  95 + noFound: 'firmware.no-firmware-text',
  96 + noMatching: 'firmware.no-firmware-matching'
  97 + }],
  98 + [FirmwareType.SOFTWARE, {
  99 + label: 'firmware.software',
  100 + required: 'firmware.software-required',
  101 + noFound: 'firmware.no-software-text',
  102 + noMatching: 'firmware.no-software-matching'
  103 + }]
  104 + ]
  105 + );
  106 +
84 private propagateChange = (v: any) => { }; 107 private propagateChange = (v: any) => { };
85 108
86 constructor(private store: Store<AppState>, 109 constructor(private store: Store<AppState>,
@@ -160,7 +183,7 @@ export class FirmwareAutocompleteComponent implements ControlValueAccessor, OnIn @@ -160,7 +183,7 @@ export class FirmwareAutocompleteComponent implements ControlValueAccessor, OnIn
160 this.entityService.getEntity(EntityType.FIRMWARE, firmwareId, {ignoreLoading: true, ignoreErrors: true}).subscribe( 183 this.entityService.getEntity(EntityType.FIRMWARE, firmwareId, {ignoreLoading: true, ignoreErrors: true}).subscribe(
161 (entity) => { 184 (entity) => {
162 this.modelValue = entity.id.id; 185 this.modelValue = entity.id.id;
163 - this.firmwareFormGroup.get('firmwareId').patchValue(entity, {emitEvent: false}); 186 + this.firmwareFormGroup.get('firmwareId').patchValue(entity);
164 }, 187 },
165 () => { 188 () => {
166 this.modelValue = null; 189 this.modelValue = null;
@@ -173,6 +196,7 @@ export class FirmwareAutocompleteComponent implements ControlValueAccessor, OnIn @@ -173,6 +196,7 @@ export class FirmwareAutocompleteComponent implements ControlValueAccessor, OnIn
173 } else { 196 } else {
174 this.modelValue = null; 197 this.modelValue = null;
175 this.firmwareFormGroup.get('firmwareId').patchValue('', {emitEvent: false}); 198 this.firmwareFormGroup.get('firmwareId').patchValue('', {emitEvent: false});
  199 + this.propagateChange(null);
176 } 200 }
177 } else { 201 } else {
178 this.modelValue = null; 202 this.modelValue = null;
@@ -209,7 +233,8 @@ export class FirmwareAutocompleteComponent implements ControlValueAccessor, OnIn @@ -209,7 +233,8 @@ export class FirmwareAutocompleteComponent implements ControlValueAccessor, OnIn
209 property: 'title', 233 property: 'title',
210 direction: Direction.ASC 234 direction: Direction.ASC
211 }); 235 });
212 - return this.firmwareService.getFirmwares(pageLink, true, {ignoreLoading: true}).pipe( 236 + return this.firmwareService.getFirmwaresInfoByDeviceProfileId(pageLink, this.deviceProfileId, this.type,
  237 + true, {ignoreLoading: true}).pipe(
213 map((data) => data && data.data.length ? data.data : null) 238 map((data) => data && data.data.length ? data.data : null)
214 ); 239 );
215 } 240 }
@@ -223,11 +248,19 @@ export class FirmwareAutocompleteComponent implements ControlValueAccessor, OnIn @@ -223,11 +248,19 @@ export class FirmwareAutocompleteComponent implements ControlValueAccessor, OnIn
223 } 248 }
224 249
225 get placeholderText(): string { 250 get placeholderText(): string {
226 - return this.labelText || 'firmware.firmware'; 251 + return this.labelText || this.firmwareTypeTranslation.get(this.type).label;
227 } 252 }
228 253
229 get requiredErrorText(): string { 254 get requiredErrorText(): string {
230 - return this.requiredText || 'firmware.firmware-required'; 255 + return this.requiredText || this.firmwareTypeTranslation.get(this.type).required;
  256 + }
  257 +
  258 + get notFoundFirmware(): string {
  259 + return this.firmwareTypeTranslation.get(this.type).noFound;
  260 + }
  261 +
  262 + get notMatchingFirmware(): string {
  263 + return this.firmwareTypeTranslation.get(this.type).noMatching;
231 } 264 }
232 265
233 firmwareTitleText(firmware: FirmwareInfo): string { 266 firmwareTitleText(firmware: FirmwareInfo): string {
@@ -498,6 +498,7 @@ export interface DeviceProfile extends BaseData<DeviceProfileId> { @@ -498,6 +498,7 @@ export interface DeviceProfile extends BaseData<DeviceProfileId> {
498 defaultRuleChainId?: RuleChainId; 498 defaultRuleChainId?: RuleChainId;
499 defaultQueueName?: string; 499 defaultQueueName?: string;
500 firmwareId?: FirmwareId; 500 firmwareId?: FirmwareId;
  501 + softwareId?: FirmwareId;
501 profileData: DeviceProfileData; 502 profileData: DeviceProfileData;
502 } 503 }
503 504
@@ -558,6 +559,7 @@ export interface Device extends BaseData<DeviceId> { @@ -558,6 +559,7 @@ export interface Device extends BaseData<DeviceId> {
558 type: string; 559 type: string;
559 label: string; 560 label: string;
560 firmwareId?: FirmwareId; 561 firmwareId?: FirmwareId;
  562 + softwareId?: FirmwareId;
561 deviceProfileId?: DeviceProfileId; 563 deviceProfileId?: DeviceProfileId;
562 deviceData?: DeviceData; 564 deviceData?: DeviceData;
563 additionalInfo?: any; 565 additionalInfo?: any;
@@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
17 import { BaseData } from '@shared/models/base-data'; 17 import { BaseData } from '@shared/models/base-data';
18 import { TenantId } from '@shared/models/id/tenant-id'; 18 import { TenantId } from '@shared/models/id/tenant-id';
19 import { FirmwareId } from '@shared/models/id/firmware-id'; 19 import { FirmwareId } from '@shared/models/id/firmware-id';
  20 +import { DeviceProfileId } from '@shared/models/id/device-profile-id';
20 21
21 export enum ChecksumAlgorithm { 22 export enum ChecksumAlgorithm {
22 MD5 = 'md5', 23 MD5 = 'md5',
@@ -32,14 +33,28 @@ export const ChecksumAlgorithmTranslationMap = new Map<ChecksumAlgorithm, string @@ -32,14 +33,28 @@ export const ChecksumAlgorithmTranslationMap = new Map<ChecksumAlgorithm, string
32 ] 33 ]
33 ); 34 );
34 35
  36 +export enum FirmwareType {
  37 + FIRMWARE = 'FIRMWARE',
  38 + SOFTWARE = 'SOFTWARE'
  39 +}
  40 +
  41 +export const FirmwareTypeTranslationMap = new Map<FirmwareType, string>(
  42 + [
  43 + [FirmwareType.FIRMWARE, 'firmware.types.firmware'],
  44 + [FirmwareType.SOFTWARE, 'firmware.types.software']
  45 + ]
  46 +);
  47 +
35 export interface FirmwareInfo extends BaseData<FirmwareId> { 48 export interface FirmwareInfo extends BaseData<FirmwareId> {
36 tenantId?: TenantId; 49 tenantId?: TenantId;
  50 + type: FirmwareType;
  51 + deviceProfileId?: DeviceProfileId;
37 title?: string; 52 title?: string;
38 version?: string; 53 version?: string;
39 hasData?: boolean; 54 hasData?: boolean;
40 fileName: string; 55 fileName: string;
41 - checksum?: ChecksumAlgorithm;  
42 - checksumAlgorithm?: string; 56 + checksum?: string;
  57 + checksumAlgorithm?: ChecksumAlgorithm;
43 contentType: string; 58 contentType: string;
44 dataSize?: number; 59 dataSize?: number;
45 additionalInfo?: any; 60 additionalInfo?: any;
@@ -1948,6 +1948,8 @@ @@ -1948,6 +1948,8 @@
1948 "idCopiedMessage": "Firmware Id has been copied to clipboard", 1948 "idCopiedMessage": "Firmware Id has been copied to clipboard",
1949 "no-firmware-matching": "No firmware matching '{{entity}}' were found.", 1949 "no-firmware-matching": "No firmware matching '{{entity}}' were found.",
1950 "no-firmware-text": "No firmwares found", 1950 "no-firmware-text": "No firmwares found",
  1951 + "no-software-matching": "No sowtware matching '{{entity}}' were found.",
  1952 + "no-software-text": "No software found",
1951 "file-name": "File name", 1953 "file-name": "File name",
1952 "file-size": "File size", 1954 "file-size": "File size",
1953 "file-size-bytes": "File size in bytes", 1955 "file-size-bytes": "File size in bytes",
@@ -1956,8 +1958,15 @@ @@ -1956,8 +1958,15 @@
1956 "firmware-required": "Firmware is required.", 1958 "firmware-required": "Firmware is required.",
1957 "search": "Search firmwares", 1959 "search": "Search firmwares",
1958 "selected-firmware": "{ count, plural, 1 {1 firmware} other {# firmwares} } selected", 1960 "selected-firmware": "{ count, plural, 1 {1 firmware} other {# firmwares} } selected",
  1961 + "software": "Software",
  1962 + "software-required": "Software is required.",
1959 "title": "Title", 1963 "title": "Title",
1960 "title-required": "Title is required.", 1964 "title-required": "Title is required.",
  1965 + "type": "Firmware type",
  1966 + "types": {
  1967 + "firmware": "Firmware",
  1968 + "software": "Software"
  1969 + },
1961 "version": "Version", 1970 "version": "Version",
1962 "version-required": "Version is required.", 1971 "version-required": "Version is required.",
1963 "warning-after-save-no-edit": "Once the firmware is saved, it will not be possible to change the title and version fields." 1972 "warning-after-save-no-edit": "Once the firmware is saved, it will not be possible to change the title and version fields."