merge with master

This commit is contained in:
Andrii Shvaika 2021-05-05 17:05:18 +03:00
commit a8dd25a7c8
6 changed files with 88 additions and 28 deletions

View File

@ -247,7 +247,7 @@
"name": "Edit firmware", "name": "Edit firmware",
"icon": "edit", "icon": "edit",
"type": "customPretty", "type": "customPretty",
"customHtml": "<form #editEntityForm=\"ngForm\" [formGroup]=\"editEntityFormGroup\"\n (ngSubmit)=\"save()\" class=\"edit-entity-form\">\n <mat-toolbar fxLayout=\"row\" color=\"primary\">\n <h2>Edit firmware {{entityName}}</h2>\n <span fxFlex></span>\n <button mat-icon-button (click)=\"cancel()\" type=\"button\">\n <mat-icon class=\"material-icons\">close</mat-icon>\n </button>\n </mat-toolbar>\n <mat-progress-bar color=\"warn\" mode=\"indeterminate\" *ngIf=\"isLoading$ | async\">\n </mat-progress-bar>\n <div style=\"height: 4px;\" *ngIf=\"!(isLoading$ | async)\"></div>\n <div mat-dialog-content fxLayout=\"column\">\n <tb-firmware-autocomplete\n [useFullEntityId]=\"true\"\n formControlName=\"firmwareId\">\n </tb-firmware-autocomplete>\n </div>\n <div mat-dialog-actions fxLayout=\"row\" fxLayoutAlign=\"end center\">\n <button mat-button color=\"primary\"\n type=\"button\"\n [disabled]=\"(isLoading$ | async)\"\n (click)=\"cancel()\" cdkFocusInitial>\n Cancel\n </button>\n <button mat-button mat-raised-button color=\"primary\"\n type=\"submit\"\n [disabled]=\"(isLoading$ | async) || editEntityForm.invalid || !editEntityForm.dirty\">\n Save\n </button>\n </div>\n</form>", "customHtml": "<form #editEntityForm=\"ngForm\" [formGroup]=\"editEntityFormGroup\"\n (ngSubmit)=\"save()\" class=\"edit-entity-form\">\n <mat-toolbar fxLayout=\"row\" color=\"primary\">\n <h2>Edit firmware {{entityName}}</h2>\n <span fxFlex></span>\n <button mat-icon-button (click)=\"cancel()\" type=\"button\">\n <mat-icon class=\"material-icons\">close</mat-icon>\n </button>\n </mat-toolbar>\n <mat-progress-bar color=\"warn\" mode=\"indeterminate\" *ngIf=\"isLoading$ | async\">\n </mat-progress-bar>\n <div style=\"height: 4px;\" *ngIf=\"!(isLoading$ | async)\"></div>\n <div *ngIf=\"entity.deviceProfileId\" mat-dialog-content fxLayout=\"column\">\n <tb-firmware-autocomplete\n [useFullEntityId]=\"true\"\n [deviceProfileId]=\"entity.deviceProfileId.id\"\n formControlName=\"firmwareId\">\n </tb-firmware-autocomplete>\n </div>\n <div mat-dialog-actions fxLayout=\"row\" fxLayoutAlign=\"end center\">\n <button mat-button color=\"primary\"\n type=\"button\"\n [disabled]=\"(isLoading$ | async)\"\n (click)=\"cancel()\" cdkFocusInitial>\n Cancel\n </button>\n <button mat-button mat-raised-button color=\"primary\"\n type=\"submit\"\n [disabled]=\"(isLoading$ | async) || editEntityForm.invalid || !editEntityForm.dirty\">\n Save\n </button>\n </div>\n</form>",
"customCss": "", "customCss": "",
"customFunction": "let $injector = widgetContext.$scope.$injector;\nlet customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));\nlet entityService = $injector.get(widgetContext.servicesMap.get('entityService'));\nlet deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));\n\nopenEditEntityDialog();\n\nfunction openEditEntityDialog() {\n customDialog.customDialog(htmlTemplate, EditEntityDialogController).subscribe();\n}\n\nfunction EditEntityDialogController(instance) {\n let vm = instance;\n\n vm.entityName = entityName;\n vm.entity = {};\n\n vm.editEntityFormGroup = vm.fb.group({\n firmwareId: [null]\n });\n\n getEntityInfo();\n\n vm.cancel = function() {\n vm.dialogRef.close(null);\n };\n\n vm.save = function() {\n vm.editEntityFormGroup.markAsPristine();\n saveEntity().subscribe(\n function () {\n // widgetContext.updateAliases();\n vm.dialogRef.close(null);\n }\n );\n };\n\n\n function getEntityInfo() {\n entityService.getEntity(entityId.entityType, entityId.id).subscribe(\n function (data) {\n vm.entity = data;\n vm.editEntityFormGroup.patchValue({\n firmwareId: vm.entity.firmwareId\n }, {emitEvent: false});\n }\n );\n }\n\n function saveEntity() {\n const formValues = vm.editEntityFormGroup.value;\n vm.entity.firmwareId = formValues.firmwareId;\n return deviceService.saveDevice(vm.entity);\n }\n}", "customFunction": "let $injector = widgetContext.$scope.$injector;\nlet customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));\nlet entityService = $injector.get(widgetContext.servicesMap.get('entityService'));\nlet deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));\n\nopenEditEntityDialog();\n\nfunction openEditEntityDialog() {\n customDialog.customDialog(htmlTemplate, EditEntityDialogController).subscribe();\n}\n\nfunction EditEntityDialogController(instance) {\n let vm = instance;\n\n vm.entityName = entityName;\n vm.entity = {};\n\n vm.editEntityFormGroup = vm.fb.group({\n firmwareId: [null]\n });\n\n getEntityInfo();\n\n vm.cancel = function() {\n vm.dialogRef.close(null);\n };\n\n vm.save = function() {\n vm.editEntityFormGroup.markAsPristine();\n saveEntity().subscribe(\n function () {\n // widgetContext.updateAliases();\n vm.dialogRef.close(null);\n }\n );\n };\n\n\n function getEntityInfo() {\n entityService.getEntity(entityId.entityType, entityId.id).subscribe(\n function (data) {\n vm.entity = data;\n vm.editEntityFormGroup.patchValue({\n firmwareId: vm.entity.firmwareId\n }, {emitEvent: false});\n }\n );\n }\n\n function saveEntity() {\n const formValues = vm.editEntityFormGroup.value;\n vm.entity.firmwareId = formValues.firmwareId;\n return deviceService.saveDevice(vm.entity);\n }\n}",
"customResources": [], "customResources": [],

View File

@ -24,10 +24,12 @@ import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.core.model.ResourceModel; import org.eclipse.leshan.core.model.ResourceModel;
import org.eclipse.leshan.core.node.LwM2mMultipleResource;
import org.eclipse.leshan.core.node.LwM2mObject; import org.eclipse.leshan.core.node.LwM2mObject;
import org.eclipse.leshan.core.node.LwM2mObjectInstance; import org.eclipse.leshan.core.node.LwM2mObjectInstance;
import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.core.node.LwM2mPath;
import org.eclipse.leshan.core.node.LwM2mResource; import org.eclipse.leshan.core.node.LwM2mResource;
import org.eclipse.leshan.core.node.LwM2mSingleResource;
import org.eclipse.leshan.core.observation.Observation; import org.eclipse.leshan.core.observation.Observation;
import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.core.request.ContentFormat;
import org.eclipse.leshan.core.request.WriteRequest; import org.eclipse.leshan.core.request.WriteRequest;
@ -277,23 +279,31 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
@Override @Override
public void onUpdateValueAfterReadResponse(Registration registration, String path, ReadResponse response, Lwm2mClientRpcRequest rpcRequest) { public void onUpdateValueAfterReadResponse(Registration registration, String path, ReadResponse response, Lwm2mClientRpcRequest rpcRequest) {
if (response.getContent() != null) { if (response.getContent() != null) {
Object value = null;
if (response.getContent() instanceof LwM2mObject) { if (response.getContent() instanceof LwM2mObject) {
LwM2mObject lwM2mObject = (LwM2mObject) response.getContent(); LwM2mObject lwM2mObject = (LwM2mObject) response.getContent();
if (rpcRequest != null) {
value = lwM2mObject.toString();
}
this.updateObjectResourceValue(registration, lwM2mObject, path); this.updateObjectResourceValue(registration, lwM2mObject, path);
} else if (response.getContent() instanceof LwM2mObjectInstance) { } else if (response.getContent() instanceof LwM2mObjectInstance) {
LwM2mObjectInstance lwM2mObjectInstance = (LwM2mObjectInstance) response.getContent(); LwM2mObjectInstance lwM2mObjectInstance = (LwM2mObjectInstance) response.getContent();
if (rpcRequest != null) {
value = lwM2mObjectInstance.toString();
}
this.updateObjectInstanceResourceValue(registration, lwM2mObjectInstance, path); this.updateObjectInstanceResourceValue(registration, lwM2mObjectInstance, path);
} else if (response.getContent() instanceof LwM2mResource) { } else if (response.getContent() instanceof LwM2mResource) {
LwM2mResource lwM2mResource = (LwM2mResource) response.getContent(); LwM2mResource lwM2mResource = (LwM2mResource) response.getContent();
if (rpcRequest != null) { if (rpcRequest != null) {
Object valueResp = lwM2mResource.isMultiInstances() ? lwM2mResource.getValues() : lwM2mResource.getValue(); value = lwM2mResource.isMultiInstances() ? ((LwM2mMultipleResource) lwM2mResource).toString() :
Object value = this.converter.convertValue(valueResp, lwM2mResource.getType(), ResourceModel.Type.STRING, ((LwM2mSingleResource) lwM2mResource).toString();
new LwM2mPath(convertPathFromIdVerToObjectId(path)));
rpcRequest.setValueMsg(String.format("%s", value));
this.sentRpcRequest(rpcRequest, response.getCode().getName(), (String) value, LOG_LW2M_VALUE);
} }
this.updateResourcesValue(registration, lwM2mResource, path); this.updateResourcesValue(registration, lwM2mResource, path);
} }
if (rpcRequest != null) {
rpcRequest.setValueMsg(String.format("%s", value));
this.sentRpcRequest(rpcRequest, response.getCode().getName(), (String) value, LOG_LW2M_VALUE);
}
} }
} }
@ -600,10 +610,10 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
/** /**
* @param registration - * @param registration -
* @param lwM2mObject - * @param lwM2mObject -
* @param path - * @param pathIdVer -
*/ */
private void updateObjectResourceValue(Registration registration, LwM2mObject lwM2mObject, String path) { private void updateObjectResourceValue(Registration registration, LwM2mObject lwM2mObject, String pathIdVer) {
LwM2mPath pathIds = new LwM2mPath(path); LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer));
lwM2mObject.getInstances().forEach((instanceId, instance) -> { lwM2mObject.getInstances().forEach((instanceId, instance) -> {
String pathInstance = pathIds.toString() + "/" + instanceId; String pathInstance = pathIds.toString() + "/" + instanceId;
this.updateObjectInstanceResourceValue(registration, instance, pathInstance); this.updateObjectInstanceResourceValue(registration, instance, pathInstance);
@ -613,10 +623,10 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
/** /**
* @param registration - * @param registration -
* @param lwM2mObjectInstance - * @param lwM2mObjectInstance -
* @param path - * @param pathIdVer -
*/ */
private void updateObjectInstanceResourceValue(Registration registration, LwM2mObjectInstance lwM2mObjectInstance, String path) { private void updateObjectInstanceResourceValue(Registration registration, LwM2mObjectInstance lwM2mObjectInstance, String pathIdVer) {
LwM2mPath pathIds = new LwM2mPath(path); LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer));
lwM2mObjectInstance.getResources().forEach((resourceId, resource) -> { lwM2mObjectInstance.getResources().forEach((resourceId, resource) -> {
String pathRez = pathIds.toString() + "/" + resourceId; String pathRez = pathIds.toString() + "/" + resourceId;
this.updateResourcesValue(registration, resource, pathRez); this.updateResourcesValue(registration, resource, pathRez);
@ -862,10 +872,9 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
public void onWriteResponseOk(Registration registration, String path, WriteRequest request) { public void onWriteResponseOk(Registration registration, String path, WriteRequest request) {
if (request.getNode() instanceof LwM2mResource) { if (request.getNode() instanceof LwM2mResource) {
this.updateResourcesValue(registration, ((LwM2mResource) request.getNode()), path); this.updateResourcesValue(registration, ((LwM2mResource) request.getNode()), path);
} } else if (request.getNode() instanceof LwM2mObjectInstance) {
else if (request.getNode() instanceof LwM2mObjectInstance) {
((LwM2mObjectInstance) request.getNode()).getResources().forEach((resId, resource) -> { ((LwM2mObjectInstance) request.getNode()).getResources().forEach((resId, resource) -> {
this.updateResourcesValue(registration, resource, path+ "/" + resId); this.updateResourcesValue(registration, resource, path + "/" + resId);
}); });
} }

View File

@ -60,6 +60,7 @@ import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -176,7 +177,7 @@ public class LwM2mTransportRequest {
* send request: path = '/3/0' node == wM2mObjectInstance * send request: path = '/3/0' node == wM2mObjectInstance
* with params == "\"resources\": {15: resource:{id:15. value:'+01'...}} * with params == "\"resources\": {15: resource:{id:15. value:'+01'...}}
**/ **/
Collection<LwM2mResource> resources = lwM2MClient.getNewResourcesForInstance( Collection<LwM2mResource> resources = lwM2MClient.getNewOneResourceForInstance(
targetIdVer, params, targetIdVer, params,
this.config.getModelProvider(), this.config.getModelProvider(),
this.converter); this.converter);
@ -191,8 +192,14 @@ public class LwM2mTransportRequest {
*/ */
else if (resultIds.isObjectInstance()) { else if (resultIds.isObjectInstance()) {
String content = (String) params; if (((ConcurrentHashMap) params).size() > 0) {
// node = Gson.fromJson((content, LwM2mNode.class); Collection<LwM2mResource> resources = lwM2MClient.getNewManyResourcesForInstance(
targetIdVer, params,
this.config.getModelProvider(),
this.converter);
request = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(),
resultIds.getObjectInstanceId(), resources);
}
} else if (resultIds.getObjectId() >= 0) { } else if (resultIds.getObjectId() >= 0) {
request = new ObserveRequest(resultIds.getObjectId()); request = new ObserveRequest(resultIds.getObjectId());
} }
@ -262,9 +269,9 @@ public class LwM2mTransportRequest {
* @param timeoutInMs - * @param timeoutInMs -
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings({"error sendRequest"})
private void sendRequest(Registration registration, LwM2mClient lwM2MClient, DownlinkRequest request, long timeoutInMs, Lwm2mClientRpcRequest rpcRequest) { private void sendRequest(Registration registration, LwM2mClient lwM2MClient, DownlinkRequest request,
long timeoutInMs, Lwm2mClientRpcRequest rpcRequest) {
context.getServer().send(registration, request, timeoutInMs, (ResponseCallback<?>) response -> { context.getServer().send(registration, request, timeoutInMs, (ResponseCallback<?>) response -> {
if (!lwM2MClient.isInit()) { if (!lwM2MClient.isInit()) {
lwM2MClient.initReadValue(this.serviceImpl, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration)); lwM2MClient.initReadValue(this.serviceImpl, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration));

View File

@ -63,6 +63,13 @@ import static org.eclipse.leshan.core.attributes.Attribute.DIMENSION;
import static org.eclipse.leshan.core.attributes.Attribute.MAXIMUM_PERIOD; import static org.eclipse.leshan.core.attributes.Attribute.MAXIMUM_PERIOD;
import static org.eclipse.leshan.core.attributes.Attribute.MINIMUM_PERIOD; import static org.eclipse.leshan.core.attributes.Attribute.MINIMUM_PERIOD;
import static org.eclipse.leshan.core.attributes.Attribute.OBJECT_VERSION; import static org.eclipse.leshan.core.attributes.Attribute.OBJECT_VERSION;
import static org.eclipse.leshan.core.model.ResourceModel.Type.BOOLEAN;
import static org.eclipse.leshan.core.model.ResourceModel.Type.FLOAT;
import static org.eclipse.leshan.core.model.ResourceModel.Type.INTEGER;
import static org.eclipse.leshan.core.model.ResourceModel.Type.OBJLNK;
import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE;
import static org.eclipse.leshan.core.model.ResourceModel.Type.STRING;
import static org.eclipse.leshan.core.model.ResourceModel.Type.TIME;
import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_KEY; import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_KEY;
import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
@ -507,4 +514,24 @@ public class LwM2mTransportUtil {
return Sets.newConcurrentHashSet(attributeListOld); return Sets.newConcurrentHashSet(attributeListOld);
} }
public static ResourceModel.Type equalsResourceTypeGetSimpleName(Object value) {
switch (value.getClass().getSimpleName()) {
case "Double":
return FLOAT;
case "Integer":
return INTEGER;
case "String":
return STRING;
case "Boolean":
return BOOLEAN;
case "byte[]":
return OPAQUE;
case "Date":
return TIME;
case "ObjectLink":
return OBJLNK;
default:
return null;
}
}
} }

View File

@ -50,6 +50,7 @@ import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPA
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.TRANSPORT_DEFAULT_LWM2M_VERSION; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.TRANSPORT_DEFAULT_LWM2M_VERSION;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromIdVerToObjectId; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromIdVerToObjectId;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getVerFromPathIdVerOrId; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getVerFromPathIdVerOrId;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.equalsResourceTypeGetSimpleName;
@Slf4j @Slf4j
public class LwM2mClient implements Cloneable { public class LwM2mClient implements Cloneable {
@ -179,23 +180,40 @@ public class LwM2mClient implements Cloneable {
} }
} }
public ResourceModel getResourceModel(String pathRez, LwM2mModelProvider modelProvider) { public ResourceModel getResourceModel(String pathIdVer, LwM2mModelProvider modelProvider) {
LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRez)); LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer));
String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId()); String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId());
String verRez = getVerFromPathIdVerOrId(pathRez); String verRez = getVerFromPathIdVerOrId(pathIdVer);
return verRez == null || verRez.equals(verSupportedObject) ? modelProvider.getObjectModel(registration) return verRez == null || verRez.equals(verSupportedObject) ? modelProvider.getObjectModel(registration)
.getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()) : null; .getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()) : null;
} }
public Collection<LwM2mResource> getNewResourcesForInstance(String pathRezIdVer, Object params, LwM2mModelProvider modelProvider, public Collection<LwM2mResource> getNewOneResourceForInstance(String pathRezIdVer, Object params, LwM2mModelProvider modelProvider,
LwM2mValueConverterImpl converter) { LwM2mValueConverterImpl converter) {
LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRezIdVer)); LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRezIdVer));
Collection<LwM2mResource> resources = ConcurrentHashMap.newKeySet(); Collection<LwM2mResource> resources = ConcurrentHashMap.newKeySet();
Map<Integer, ResourceModel> resourceModels = modelProvider.getObjectModel(registration) Map<Integer, ResourceModel> resourceModels = modelProvider.getObjectModel(registration)
.getObjectModel(pathIds.getObjectId()).resources; .getObjectModel(pathIds.getObjectId()).resources;
resourceModels.forEach((resId, resourceModel) -> { resourceModels.forEach((resId, resourceModel) -> {
if (resId == pathIds.getResourceId()) { if (resId == pathIds.getResourceId()) {
resources.add(LwM2mSingleResource.newResource(resId, converter.convertValue(params, ResourceModel.Type.STRING, resourceModel.type, pathIds), resourceModel.type)); resources.add(LwM2mSingleResource.newResource(resId, converter.convertValue(params,
equalsResourceTypeGetSimpleName(params), resourceModel.type, pathIds), resourceModel.type));
}});
return resources;
}
public Collection<LwM2mResource> getNewManyResourcesForInstance(String pathRezIdVer, Object params, LwM2mModelProvider modelProvider,
LwM2mValueConverterImpl converter) {
LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRezIdVer));
Collection<LwM2mResource> resources = ConcurrentHashMap.newKeySet();
Map<Integer, ResourceModel> resourceModels = modelProvider.getObjectModel(registration)
.getObjectModel(pathIds.getObjectId()).resources;
resourceModels.forEach((resId, resourceModel) -> {
if (((ConcurrentHashMap) params).containsKey(String.valueOf(resId))) {
Object value = ((ConcurrentHashMap) params).get((String.valueOf(resId)));
resources.add(LwM2mSingleResource.newResource(resId,
converter.convertValue(value, equalsResourceTypeGetSimpleName(value), resourceModel.type, pathIds), resourceModel.type));
}}); }});
return resources; return resources;

View File

@ -177,7 +177,6 @@ public class LwM2mValueConverterImpl implements LwM2mValueConverter {
} }
default: default:
} }
throw new CodecException("Invalid value type for resource %s, expected %s, got %s", resourcePath, expectedType, throw new CodecException("Invalid value type for resource %s, expected %s, got %s", resourcePath, expectedType,
currentType); currentType);
} }