Lwm2m: add Update Fw && Sw (#4557)

* Lwm2m: add Update Fw && Fix bug toLwM2mObject (not add Lwm2mObject without resources)

* Lwm2m: fix bug test

* Lwm2m: fw_update_start

* Lwm2m: fw_update send state

* Lwm2m: add     registration_store_pool_size: "${LWM2M_REGISTRATION_STORE_POOL_SIZE:100}"
               clean_period_in_sec: "${LWM2M_CLEAN_PERIOD_IN_SEC:2}"

* Lwm2m: add Update Execute

* Lwm2m: add Update Execute Successful

* Lwm2m: send state to tningsboard if only Successful
This commit is contained in:
nickAS21 2021-05-11 18:27:35 +03:00 committed by GitHub
parent 81820a6b24
commit a703dead7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 931 additions and 213 deletions

View File

@ -24,8 +24,9 @@ import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.FirmwareInfo;
import org.thingsboard.server.common.data.firmware.FirmwareUtil;
import org.thingsboard.server.common.data.firmware.FirmwareType;
import org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus;
import org.thingsboard.server.common.data.firmware.FirmwareUtil;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.FirmwareId;
import org.thingsboard.server.common.data.id.TenantId;
@ -66,11 +67,11 @@ import static org.thingsboard.server.common.data.firmware.FirmwareKey.STATE;
import static org.thingsboard.server.common.data.firmware.FirmwareKey.TITLE;
import static org.thingsboard.server.common.data.firmware.FirmwareKey.TS;
import static org.thingsboard.server.common.data.firmware.FirmwareKey.VERSION;
import static org.thingsboard.server.common.data.firmware.FirmwareType.FIRMWARE;
import static org.thingsboard.server.common.data.firmware.FirmwareType.SOFTWARE;
import static org.thingsboard.server.common.data.firmware.FirmwareUtil.getAttributeKey;
import static org.thingsboard.server.common.data.firmware.FirmwareUtil.getTargetTelemetryKey;
import static org.thingsboard.server.common.data.firmware.FirmwareUtil.getTelemetryKey;
import static org.thingsboard.server.common.data.firmware.FirmwareType.FIRMWARE;
import static org.thingsboard.server.common.data.firmware.FirmwareType.SOFTWARE;
@Slf4j
@Service

View File

@ -44,6 +44,7 @@ import java.util.Base64;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_KEY;
import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_SEARCH_TEXT;
@ -130,7 +131,7 @@ public class DefaultTbResourceService implements TbResourceService {
List<TbResource> resources = resourceService.findTenantResourcesByResourceTypeAndObjectIds(tenantId, ResourceType.LWM2M_MODEL,
objectIds);
return resources.stream()
.map(this::toLwM2mObject)
.flatMap(s -> Stream.ofNullable(toLwM2mObject(s)))
.sorted(getComparator(sortProperty, sortOrder))
.collect(Collectors.toList());
}
@ -141,7 +142,7 @@ public class DefaultTbResourceService implements TbResourceService {
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
PageData<TbResource> resourcePageData = resourceService.findTenantResourcesByResourceTypeAndPageLink(tenantId, ResourceType.LWM2M_MODEL, pageLink);
return resourcePageData.getData().stream()
.map(this::toLwM2mObject)
.flatMap(s -> Stream.ofNullable(toLwM2mObject(s)))
.sorted(getComparator(sortProperty, sortOrder))
.collect(Collectors.toList());
}
@ -190,9 +191,14 @@ public class DefaultTbResourceService implements TbResourceService {
resources.add(lwM2MResourceObserve);
}
});
instance.setResources(resources.toArray(LwM2mResourceObserve[]::new));
lwM2mObject.setInstances(new LwM2mInstance[]{instance});
return lwM2mObject;
if (resources.size() > 0) {
instance.setResources(resources.toArray(LwM2mResourceObserve[]::new));
lwM2mObject.setInstances(new LwM2mInstance[]{instance});
return lwM2mObject;
}
else {
return null;
}
}
} catch (IOException | InvalidDDFFileException e) {
log.error("Could not parse the XML of objectModel with name [{}]", resource.getSearchText(), e);

View File

@ -672,6 +672,8 @@ transport:
recommended_supported_groups: "${LWM2M_RECOMMENDED_SUPPORTED_GROUPS:true}"
response_pool_size: "${LWM2M_RESPONSE_POOL_SIZE:100}"
registered_pool_size: "${LWM2M_REGISTERED_POOL_SIZE:10}"
registration_store_pool_size: "${LWM2M_REGISTRATION_STORE_POOL_SIZE:100}"
clean_period_in_sec: "${LWM2M_CLEAN_PERIOD_IN_SEC:2}"
update_registered_pool_size: "${LWM2M_UPDATE_REGISTERED_POOL_SIZE:10}"
un_registered_pool_size: "${LWM2M_UN_REGISTERED_POOL_SIZE:10}"
log_max_length: "${LWM2M_LOG_MAX_LENGTH:100}"

View File

@ -32,7 +32,6 @@ import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.controller.AbstractControllerTest;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.service.AbstractServiceTest;
import org.thingsboard.server.dao.service.DaoSqlTest;
import java.util.ArrayList;
@ -57,7 +56,7 @@ public class BaseTbResourceServiceTest extends AbstractControllerTest {
"<Resources>\n" +
"<Item ID=\"0\">\n" +
"<Name>LWM2M</Name>\n" +
"<Operations></Operations>\n" +
"<Operations>RW</Operations>\n" +
"<MultipleInstances>Single</MultipleInstances>\n" +
"<Mandatory>Mandatory</Mandatory>\n" +
"<Type>String</Type>\n" +

View File

@ -92,26 +92,6 @@ public class DataConstants {
public static final String CLIENT_ID = "clientId";
public static final String USERNAME = "username";
public static final String PASSWORD = "password";
//<<<<<<< HEAD
//=======
// //firmware
// //telemetry
// public static final String CURRENT_FIRMWARE_TITLE = "current_fw_title";
// public static final String CURRENT_FIRMWARE_VERSION = "current_fw_version";
// public static final String TARGET_FIRMWARE_TITLE = "target_fw_title";
// public static final String TARGET_FIRMWARE_VERSION = "target_fw_version";
// public static final String TARGET_FIRMWARE_TS = "target_fw_ts";
// public static final String FIRMWARE_STATE = "fw_state";
//
// //attributes
// //telemetry
// public static final String FIRMWARE_TITLE = "fw_title";
// public static final String FIRMWARE_VERSION = "fw_version";
// public static final String FIRMWARE_SIZE = "fw_size";
// public static final String FIRMWARE_CHECKSUM = "fw_checksum";
// public static final String FIRMWARE_CHECKSUM_ALGORITHM = "fw_checksum_algorithm";
//>>>>>>> origin/master
public static final String EDGE_MSG_SOURCE = "edge";
public static final String MSG_SOURCE_KEY = "source";

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.firmware;
package org.thingsboard.server.common.data.firmware;
public enum FirmwareUpdateStatus {
QUEUED, INITIATED, DOWNLOADING, DOWNLOADED, VERIFIED, UPDATING, UPDATED, FAILED

View File

@ -64,6 +64,14 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig {
@Value("${transport.lwm2m.registered_pool_size:}")
private int registeredPoolSize;
@Getter
@Value("${transport.lwm2m.registration_store_pool_size:}")
private int registrationStorePoolSize;
@Getter
@Value("${transport.lwm2m.clean_period_in_sec:}")
private int cleanPeriodInSec;
@Getter
@Value("${transport.lwm2m.update_registered_pool_size:}")
private int updateRegisteredPoolSize;

View File

@ -44,6 +44,7 @@ import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.firmware.FirmwareKey;
import org.thingsboard.server.common.data.firmware.FirmwareType;
import org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus;
import org.thingsboard.server.common.data.firmware.FirmwareUtil;
import org.thingsboard.server.common.data.id.FirmwareId;
import org.thingsboard.server.common.transport.TransportService;
@ -84,19 +85,21 @@ import java.util.stream.Collectors;
import static org.eclipse.californium.core.coap.CoAP.ResponseCode.BAD_REQUEST;
import static org.eclipse.leshan.core.attributes.Attribute.OBJECT_VERSION;
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.transport.lwm2m.server.LwM2mTransportServerHelper.getValueFromKvProto;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.CLIENT_NOT_AUTHORIZED;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.DEVICE_ATTRIBUTES_REQUEST;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FR_OBJECT_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FR_PATH_RESOURCE_VER_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.EqualsFwSateToFirmwareUpdateStatus;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_RESULT_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_STATE_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_ERROR;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_INFO;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_VALUE;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LWM2M_STRATEGY_2;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.DISCOVER;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.DISCOVER_All;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.EXECUTE;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_CANCEL;
@ -105,6 +108,7 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.L
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_ATTRIBUTES;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_REPLACE;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_UPDATE;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertJsonArrayToSet;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromIdVerToObjectId;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer;
@ -124,12 +128,12 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
private final TransportService transportService;
private final LwM2mTransportContext context;
private final LwM2MTransportServerConfig config;
private final FirmwareDataCache firmwareDataCache;
private final LwM2mTransportServerHelper helper;
public final LwM2MTransportServerConfig config;
public final FirmwareDataCache firmwareDataCache;
public final LwM2mTransportServerHelper helper;
private final LwM2MJsonAdaptor adaptor;
private final LwM2mClientContext clientContext;
private final LwM2mTransportRequest lwM2mTransportRequest;
public final LwM2mTransportRequest lwM2mTransportRequest;
public DefaultLwM2MTransportMsgHandler(TransportService transportService, LwM2MTransportServerConfig config, LwM2mTransportServerHelper helper,
LwM2mClientContext clientContext,
@ -182,6 +186,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), null);
transportService.process(sessionInfo, TransportProtos.SubscribeToRPCMsg.newBuilder().build(), null);
this.getInfoFirmwareUpdate(lwM2MClient);
this.getInfoSoftwareUpdate(lwM2MClient);
this.initLwM2mFromClientValue(registration, lwM2MClient);
this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client create after Registration", registration.getId());
} else {
@ -327,9 +332,16 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
String pathName = tsKvProto.getKv().getKey();
String pathIdVer = this.getPresentPathIntoProfile(sessionInfo, pathName);
Object valueNew = getValueFromKvProto(tsKvProto.getKv());
//TODO: react on change of the firmware name.
if (FirmwareUtil.getAttributeKey(FirmwareType.FIRMWARE, FirmwareKey.VERSION).equals(pathName) && !valueNew.equals(lwM2MClient.getFrUpdate().getCurrentFwVersion())) {
if ((FirmwareUtil.getAttributeKey(FirmwareType.FIRMWARE, FirmwareKey.VERSION).equals(pathName)
&& (!valueNew.equals(lwM2MClient.getFwUpdate().getCurrentVersion())))
|| (FirmwareUtil.getAttributeKey(FirmwareType.FIRMWARE, FirmwareKey.TITLE).equals(pathName)
&& (!valueNew.equals(lwM2MClient.getFwUpdate().getCurrentTitle())))) {
this.getInfoFirmwareUpdate(lwM2MClient);
} else if ((FirmwareUtil.getAttributeKey(FirmwareType.SOFTWARE, FirmwareKey.VERSION).equals(pathName)
&& (!valueNew.equals(lwM2MClient.getSwUpdate().getCurrentVersion())))
|| (FirmwareUtil.getAttributeKey(FirmwareType.SOFTWARE, FirmwareKey.TITLE).equals(pathName)
&& (!valueNew.equals(lwM2MClient.getSwUpdate().getCurrentTitle())))) {
this.getInfoSoftwareUpdate(lwM2MClient);
}
if (pathIdVer != null) {
ResourceModel resourceModel = lwM2MClient.getResourceModel(pathIdVer, this.config
@ -354,8 +366,8 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
msg.getSharedUpdatedList().forEach(tsKvProto -> {
String pathName = tsKvProto.getKv().getKey();
Object valueNew = getValueFromKvProto(tsKvProto.getKv());
if (FirmwareUtil.getAttributeKey(FirmwareType.FIRMWARE, FirmwareKey.VERSION).equals(pathName) && !valueNew.equals(lwM2MClient.getFrUpdate().getCurrentFwVersion())) {
lwM2MClient.getFrUpdate().setCurrentFwVersion((String) valueNew);
if (FirmwareUtil.getAttributeKey(FirmwareType.FIRMWARE, FirmwareKey.VERSION).equals(pathName) && !valueNew.equals(lwM2MClient.getFwUpdate().getCurrentVersion())) {
lwM2MClient.getFwUpdate().setCurrentVersion((String) valueNew);
}
});
log.info("[{}] delete [{}] onAttributeUpdate", msg.getSharedDeletedList(), sessionInfo);
@ -460,22 +472,22 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
.getAsJsonObject().toString(), new TypeToken<ConcurrentHashMap<String, Object>>() {
}.getType());
if (WRITE_UPDATE == lwm2mClientRpcRequest.getTypeOper()) {
ConcurrentHashMap<String, Object> paramsResourceId = convertParamsToResourceId (params, sessionInfo);
ConcurrentHashMap<String, Object> paramsResourceId = convertParamsToResourceId(params, sessionInfo);
if (paramsResourceId.size() > 0) {
lwm2mClientRpcRequest.setParams(paramsResourceId);
}
}
else {
} else {
lwm2mClientRpcRequest.setParams(params);
}
}
else if (rpcRequest.has(lwm2mClientRpcRequest.paramsKey) && rpcRequest.get(lwm2mClientRpcRequest.paramsKey).isJsonArray()) {
} else if (rpcRequest.has(lwm2mClientRpcRequest.paramsKey) && rpcRequest.get(lwm2mClientRpcRequest.paramsKey).isJsonArray()) {
new Gson().fromJson(rpcRequest.get(lwm2mClientRpcRequest.paramsKey)
.getAsJsonObject().toString(), new TypeToken<ConcurrentHashMap<String, Object>>() {
}.getType());
}
lwm2mClientRpcRequest.setSessionInfo(sessionInfo);
if (OBSERVE_READ_ALL != lwm2mClientRpcRequest.getTypeOper() && lwm2mClientRpcRequest.getTargetIdVer() == null) {
if (!(OBSERVE_READ_ALL == lwm2mClientRpcRequest.getTypeOper()
|| DISCOVER_All == lwm2mClientRpcRequest.getTypeOper())
&& lwm2mClientRpcRequest.getTargetIdVer() == null) {
lwm2mClientRpcRequest.setErrorMsg(lwm2mClientRpcRequest.targetIdVerKey + " and " +
lwm2mClientRpcRequest.keyNameKey + " is null or bad format");
}
@ -499,12 +511,12 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
return lwm2mClientRpcRequest;
}
private ConcurrentHashMap<String, Object> convertParamsToResourceId (ConcurrentHashMap<String, Object> params,
SessionInfoProto sessionInfo) {
private ConcurrentHashMap<String, Object> convertParamsToResourceId(ConcurrentHashMap<String, Object> params,
SessionInfoProto sessionInfo) {
ConcurrentHashMap<String, Object> paramsIdVer = new ConcurrentHashMap<>();
params.forEach((k, v) -> {
String targetIdVer = this.getPresentPathIntoProfile(sessionInfo, k);
if (targetIdVer != null ) {
if (targetIdVer != null) {
LwM2mPath targetId = new LwM2mPath(convertPathFromIdVerToObjectId(targetIdVer));
if (targetId.isResource()) {
paramsIdVer.put(String.valueOf(targetId.getResourceId()), v);
@ -640,7 +652,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
/**
* @param registration -
* @param lwM2mObject -
* @param pathIdVer -
* @param pathIdVer -
*/
private void updateObjectResourceValue(Registration registration, LwM2mObject lwM2mObject, String pathIdVer) {
LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer));
@ -678,18 +690,31 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
LwM2mClient lwM2MClient = clientContext.getOrRegister(registration);
if (lwM2MClient.saveResourceValue(path, lwM2mResource, this.config
.getModelProvider())) {
if (FR_PATH_RESOURCE_VER_ID.equals(convertPathFromIdVerToObjectId(path)) &&
lwM2MClient.getFrUpdate().getCurrentFwVersion() != null
&& !lwM2MClient.getFrUpdate().getCurrentFwVersion().equals(lwM2MClient.getFrUpdate().getClientFwVersion())
&& lwM2MClient.isUpdateFw()) {
/** version != null
* set setClient_fw_info... = value
**/
if (lwM2MClient.getFwUpdate().isInfoFwSwUpdate()) {
lwM2MClient.getFwUpdate().initReadValue(this, path);
}
if (lwM2MClient.getSwUpdate().isInfoFwSwUpdate()) {
lwM2MClient.getSwUpdate().initReadValue(this, path);
}
if (lwM2MClient.getFwUpdate().getStateUpdate() != null
&& !FirmwareUpdateStatus.DOWNLOADING.name().equals(lwM2MClient.getFwUpdate().getStateUpdate())
&& (convertPathFromObjectIdToIdVer(FW_STATE_ID, registration).equals(path)
|| convertPathFromObjectIdToIdVer(FW_RESULT_ID, registration).equals(path))) {
Long stateFw = (Long) lwM2MClient.getResourceValue(null, FW_STATE_ID);
Long updateResultFw = (Long) lwM2MClient.getResourceValue(null, FW_RESULT_ID);
FirmwareUpdateStatus state = EqualsFwSateToFirmwareUpdateStatus(LwM2mTransportUtil.StateFw.fromStateFwByCode(stateFw.intValue()),
LwM2mTransportUtil.UpdateResultFw.fromUpdateResultFwByCode(updateResultFw.intValue()));
if (state != FirmwareUpdateStatus.DOWNLOADING && state != FirmwareUpdateStatus.DOWNLOADED) {
lwM2MClient.getFwUpdate().setStateUpdate(state.name());
lwM2MClient.getFwUpdate().sendLogs(OBSERVE.name());
}
log.warn ("update Resource [{}]", lwM2mResource);
}
if (FirmwareUpdateStatus.DOWNLOADED.name().equals(lwM2MClient.getSwUpdate().getStateUpdate())) {
/** version != null
* set setClient_fw_version = value
**/
lwM2MClient.setUpdateFw(false);
lwM2MClient.getFrUpdate().setClientFwVersion(lwM2mResource.getValue().toString());
log.warn("updateFirmwareClient3");
this.updateFirmwareClient(lwM2MClient);
}
Set<String> paths = new HashSet<>();
paths.add(path);
@ -845,7 +870,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
Object finalvalueKvProto = valueKvProto;
Gson gson = new GsonBuilder().create();
resourceValue.getValues().forEach((k, v) -> {
Object val = this.converter.convertValue(resourceValue.getValue(), currentType, expectedType,
Object val = this.converter.convertValue(v, currentType, expectedType,
new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer)));
JsonElement element = gson.toJsonTree(val, val.getClass());
((JsonObject) finalvalueKvProto).add(String.valueOf(k), element);
@ -937,7 +962,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
*/
private void onDeviceProfileUpdate(Set<String> registrationIds, DeviceProfile deviceProfile) {
LwM2mClientProfile lwM2MClientProfileOld = clientContext.getProfiles().get(deviceProfile.getUuidId()).clone();
if (clientContext.toClientProfile(deviceProfile) != null) {
if (clientContext.profileUpdate(deviceProfile) != null) {
// #1
JsonArray attributeOld = lwM2MClientProfileOld.getPostAttributeProfile();
Set<String> attributeSetOld = convertJsonArrayToSet(attributeOld);
@ -947,7 +972,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
JsonObject keyNameOld = lwM2MClientProfileOld.getPostKeyNameProfile();
JsonObject attributeLwm2mOld = lwM2MClientProfileOld.getPostAttributeLwm2mProfile();
LwM2mClientProfile lwM2MClientProfileNew = clientContext.getProfiles().get(deviceProfile.getUuidId());
LwM2mClientProfile lwM2MClientProfileNew = clientContext.getProfiles().get(deviceProfile.getUuidId()).clone();
JsonArray attributeNew = lwM2MClientProfileNew.getPostAttributeProfile();
Set<String> attributeSetNew = convertJsonArrayToSet(attributeNew);
JsonArray telemetryNew = lwM2MClientProfileNew.getPostTelemetryProfile();
@ -996,7 +1021,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
Registration registration = clientContext.getRegistration(registrationId);
this.readObserveFromProfile(registration, sendAttrToThingsboard.getPathPostParametersAdd(), READ);
// send attr/telemetry to tingsboard for new path
this.updateAttrTelemetry(registration, sendAttrToThingsboard.getPathPostParametersAdd());
// this.updateAttrTelemetry(registration, sendAttrToThingsboard.getPathPostParametersAdd());
});
}
// #4.2 del
@ -1275,7 +1300,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
* @param registration - Registration LwM2M Client
* @return - sessionInfo after access connect client
*/
private SessionInfoProto getSessionInfoOrCloseSession(Registration registration) {
public SessionInfoProto getSessionInfoOrCloseSession(Registration registration) {
return getSessionInfoOrCloseSession(clientContext.getOrRegister(registration));
}
@ -1331,62 +1356,72 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
}
public void getInfoFirmwareUpdate(LwM2mClient lwM2MClient) {
SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(lwM2MClient);
if (sessionInfo != null) {
TransportProtos.GetFirmwareRequestMsg getFirmwareRequestMsg = TransportProtos.GetFirmwareRequestMsg.newBuilder()
.setDeviceIdMSB(sessionInfo.getDeviceIdMSB())
.setDeviceIdLSB(sessionInfo.getDeviceIdLSB())
.setTenantIdMSB(sessionInfo.getTenantIdMSB())
.setTenantIdLSB(sessionInfo.getTenantIdLSB())
.setType(FirmwareType.FIRMWARE.name())
.build();
transportService.process(sessionInfo, getFirmwareRequestMsg,
new TransportServiceCallback<>() {
@Override
public void onSuccess(TransportProtos.GetFirmwareResponseMsg response) {
if (TransportProtos.ResponseStatus.SUCCESS.equals(response.getResponseStatus())) {
lwM2MClient.getFrUpdate().setCurrentFwVersion(response.getVersion());
lwM2MClient.getFrUpdate().setCurrentFwId(new FirmwareId(new UUID(response.getFirmwareIdMSB(), response.getFirmwareIdLSB())).getId());
lwM2MClient.setUpdateFw(true);
readRequestToClientFirmwareVer(lwM2MClient.getRegistration());
} else {
log.trace("Firmware [{}] [{}]", lwM2MClient.getDeviceName(), response.getResponseStatus().toString());
if (lwM2MClient.getRegistration().getSupportedVersion(FW_ID) != null) {
SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(lwM2MClient);
if (sessionInfo != null) {
DefaultLwM2MTransportMsgHandler serviceImpl = this;
transportService.process(sessionInfo, createFirmwareRequestMsg(sessionInfo, FirmwareType.FIRMWARE.name()),
new TransportServiceCallback<>() {
@Override
public void onSuccess(TransportProtos.GetFirmwareResponseMsg response) {
if (TransportProtos.ResponseStatus.SUCCESS.equals(response.getResponseStatus())
&& response.getType().equals(FirmwareType.FIRMWARE.name())) {
lwM2MClient.getFwUpdate().setCurrentVersion(response.getVersion());
lwM2MClient.getFwUpdate().setCurrentTitle(response.getTitle());
lwM2MClient.getFwUpdate().setCurrentId(new FirmwareId(new UUID(response.getFirmwareIdMSB(), response.getFirmwareIdLSB())).getId());
lwM2MClient.getFwUpdate().sendReadInfo(serviceImpl);
} else {
log.trace("Firmware [{}] [{}]", lwM2MClient.getDeviceName(), response.getResponseStatus().toString());
}
}
}
@Override
public void onError(Throwable e) {
log.trace("Failed to process credentials ", e);
}
});
@Override
public void onError(Throwable e) {
log.warn("Failed to process firmwareUpdate ", e);
}
});
}
}
}
/**
* @param registration
*/
public void readRequestToClientFirmwareVer(Registration registration) {
String pathIdVer = convertPathFromObjectIdToIdVer(FR_PATH_RESOURCE_VER_ID, registration);
lwM2mTransportRequest.sendAllRequest(registration, pathIdVer, READ, ContentFormat.TLV.getName(),
null, config.getTimeout(), null);
}
public void getInfoSoftwareUpdate(LwM2mClient lwM2MClient) {
if (lwM2MClient.getRegistration().getSupportedVersion(SW_ID) != null) {
SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(lwM2MClient);
if (sessionInfo != null) {
DefaultLwM2MTransportMsgHandler serviceImpl = this;
transportService.process(sessionInfo, createFirmwareRequestMsg(sessionInfo, FirmwareType.SOFTWARE.name()),
new TransportServiceCallback<>() {
@Override
public void onSuccess(TransportProtos.GetFirmwareResponseMsg response) {
if (TransportProtos.ResponseStatus.SUCCESS.equals(response.getResponseStatus())
&& response.getType().equals(FirmwareType.SOFTWARE.name())) {
lwM2MClient.getSwUpdate().setCurrentVersion(response.getVersion());
lwM2MClient.getSwUpdate().setCurrentTitle(response.getTitle());
lwM2MClient.getSwUpdate().setCurrentId(new FirmwareId(new UUID(response.getFirmwareIdMSB(), response.getFirmwareIdLSB())).getId());
lwM2MClient.getSwUpdate().sendReadInfo(serviceImpl);
} else {
log.trace("Software [{}] [{}]", lwM2MClient.getDeviceName(), response.getResponseStatus().toString());
}
}
/**
* @param lwM2MClient -
*/
public void updateFirmwareClient(LwM2mClient lwM2MClient) {
if (!lwM2MClient.getFrUpdate().getCurrentFwVersion().equals(lwM2MClient.getFrUpdate().getClientFwVersion())) {
int chunkSize = 0;
int chunk = 0;
byte[] firmwareChunk = firmwareDataCache.get(lwM2MClient.getFrUpdate().getCurrentFwId().toString(), chunkSize, chunk);
String verSupportedObject = lwM2MClient.getRegistration().getSupportedObject().get(FR_OBJECT_ID);
String targetIdVer = LWM2M_SEPARATOR_PATH + FR_OBJECT_ID + LWM2M_SEPARATOR_KEY + verSupportedObject + LWM2M_SEPARATOR_PATH + 0 + LWM2M_SEPARATOR_PATH + 0;
lwM2mTransportRequest.sendAllRequest(lwM2MClient.getRegistration(), targetIdVer, WRITE_REPLACE, ContentFormat.OPAQUE.getName(),
firmwareChunk, config.getTimeout(), null);
log.warn("updateFirmwareClient [{}] [{}]", lwM2MClient.getFrUpdate().getCurrentFwVersion(), lwM2MClient.getFrUpdate().getClientFwVersion());
@Override
public void onError(Throwable e) {
log.trace("Failed to process softwareUpdate ", e);
}
});
}
}
}
private TransportProtos.GetFirmwareRequestMsg createFirmwareRequestMsg(SessionInfoProto sessionInfo, String nameFwSW) {
return TransportProtos.GetFirmwareRequestMsg.newBuilder()
.setDeviceIdMSB(sessionInfo.getDeviceIdMSB())
.setDeviceIdLSB(sessionInfo.getDeviceIdLSB())
.setTenantIdMSB(sessionInfo.getTenantIdMSB())
.setTenantIdLSB(sessionInfo.getTenantIdLSB())
.setType(nameFwSW)
.build();
}
/**
* !!! sharedAttr === profileAttr !!!

View File

@ -24,11 +24,13 @@ import org.eclipse.leshan.core.util.Hex;
import org.eclipse.leshan.server.californium.LeshanServer;
import org.eclipse.leshan.server.californium.LeshanServerBuilder;
import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore;
import org.eclipse.leshan.server.californium.registration.InMemoryRegistrationStore;
import org.eclipse.leshan.server.model.LwM2mModelProvider;
import org.eclipse.leshan.server.security.DefaultAuthorizer;
import org.eclipse.leshan.server.security.EditableSecurityStore;
import org.eclipse.leshan.server.security.SecurityChecker;
import org.springframework.stereotype.Component;
import org.thingsboard.common.util.ThingsBoardThreadFactory;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
@ -57,6 +59,8 @@ import java.security.spec.InvalidParameterSpecException;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Arrays;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8;
@ -81,6 +85,7 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
private final CaliforniumRegistrationStore registrationStore;
private final EditableSecurityStore securityStore;
private final LwM2mClientContext lwM2mClientContext;
private ScheduledExecutorService registrationStoreExecutor;
private LeshanServer server;
@ -112,6 +117,9 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
}
private LeshanServer getLhServer() {
// this.registrationStoreExecutor = (ScheduledExecutorService) ThingsBoardExecutors.newWorkStealingPool(this.config.getRegistrationStorePoolSize(), "LwM2M registrationStore");
this.registrationStoreExecutor = Executors.newScheduledThreadPool(this.config.getRegistrationStorePoolSize(), ThingsBoardThreadFactory.forName("LwM2M registrationStore"));
LeshanServerBuilder builder = new LeshanServerBuilder();
builder.setLocalAddress(config.getHost(), config.getPort());
builder.setLocalSecureAddress(config.getSecureHost(), config.getSecurePort());
@ -119,6 +127,9 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
/* Use a magic converter to support bad type send by the UI. */
builder.setEncoder(new DefaultLwM2mNodeEncoder(LwM2mValueConverterImpl.getInstance()));
/* InMemoryRegistrationStore(ScheduledExecutorService schedExecutor, long cleanPeriodInSec) */
InMemoryRegistrationStore registrationStore = new InMemoryRegistrationStore(this.registrationStoreExecutor, this.config.getCleanPeriodInSec());
builder.setRegistrationStore(registrationStore);
/* Create CoAP Config */
builder.setCoapConfig(getCoapConfig(config.getPort(), config.getSecurePort()));

View File

@ -88,7 +88,7 @@ public class LwM2mServerListener {
public void cancelled(Observation observation) {
String msg = String.format("%s: Cancel Observation %s.", LOG_LW2M_INFO, observation.getPath());
service.sendLogsToThingsboard(msg, observation.getRegistrationId());
log.trace(msg);
log.warn(msg);
}
@Override

View File

@ -19,6 +19,7 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.californium.core.coap.CoAP;
import org.eclipse.californium.core.coap.Response;
import org.eclipse.leshan.core.Link;
import org.eclipse.leshan.core.model.ResourceModel;
import org.eclipse.leshan.core.node.LwM2mNode;
import org.eclipse.leshan.core.node.LwM2mPath;
@ -48,6 +49,7 @@ import org.eclipse.leshan.core.util.Hex;
import org.eclipse.leshan.core.util.NamedThreadFactory;
import org.eclipse.leshan.server.registration.Registration;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus;
import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
@ -69,14 +71,16 @@ import static org.eclipse.californium.core.coap.CoAP.ResponseCode.CONTENT;
import static org.eclipse.leshan.core.ResponseCode.BAD_REQUEST;
import static org.eclipse.leshan.core.ResponseCode.NOT_FOUND;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.DEFAULT_TIMEOUT;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FR_PATH_RESOURCE_VER_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_PACKAGE_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_ERROR;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_INFO;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_VALUE;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.DISCOVER_All;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_CANCEL;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_READ_ALL;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.RESPONSE_CHANNEL;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_PACKAGE_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromIdVerToObjectId;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.createWriteAttributeRequest;
@ -132,7 +136,13 @@ public class LwM2mTransportRequest {
break;
case OBSERVE:
if (resultIds.isResource()) {
request = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId());
Set<Observation> observations = context.getServer().getObservationService().getObservations(registration);
Set<Observation> paths = observations.stream().filter(observation -> observation.getPath().equals(resultIds)).collect(Collectors.toSet());
if (paths.size() == 0) {
request = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId());
} else {
request = new ReadRequest(contentFormat, target);
}
} else if (resultIds.isObjectInstance()) {
request = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId());
} else if (resultIds.getObjectId() >= 0) {
@ -197,11 +207,10 @@ public class LwM2mTransportRequest {
targetIdVer, params,
this.config.getModelProvider(),
this.converter);
if (resources.size()>0) {
if (resources.size() > 0) {
request = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(),
resultIds.getObjectInstanceId(), resources);
}
else {
} else {
Lwm2mClientRpcRequest rpcRequestClone = (Lwm2mClientRpcRequest) rpcRequest.clone();
if (rpcRequestClone != null) {
String errorMsg = String.format("Path %s params is not valid", targetIdVer);
@ -250,15 +259,21 @@ public class LwM2mTransportRequest {
String errorMsg = String.format("Path %s not found in object version", targetIdVer);
serviceImpl.sentRpcRequest(rpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR);
}
} else if (OBSERVE_READ_ALL.name().equals(typeOper.name())) {
Set<Observation> observations = context.getServer().getObservationService().getObservations(registration);
Set<String> observationPaths = observations.stream().map(observation -> observation.getPath().toString()).collect(Collectors.toUnmodifiableSet());
String msg = String.format("%s: type operation %s observation paths - %s", LOG_LW2M_INFO,
OBSERVE_READ_ALL.type, observationPaths);
} else if (OBSERVE_READ_ALL.name().equals(typeOper.name()) || DISCOVER_All.name().equals(typeOper.name())) {
Set<String> paths;
if (OBSERVE_READ_ALL.name().equals(typeOper.name())) {
Set<Observation> observations = context.getServer().getObservationService().getObservations(registration);
paths = observations.stream().map(observation -> observation.getPath().toString()).collect(Collectors.toUnmodifiableSet());
} else {
Link[] objectLinks = registration.getSortedObjectLinks();
paths = Arrays.stream(objectLinks).map(link -> link.toString()).collect(Collectors.toUnmodifiableSet());
}
String msg = String.format("%s: type operation %s paths - %s", LOG_LW2M_INFO,
OBSERVE_READ_ALL.type, paths);
serviceImpl.sendLogsToThingsboard(msg, registration.getId());
log.trace("[{}] [{}], [{}]", typeOper.name(), registration.getEndpoint(), msg);
log.warn("[{}] [{}], [{}]", typeOper.name(), registration.getEndpoint(), msg);
if (rpcRequest != null) {
String valueMsg = String.format("Observation paths - %s", observationPaths);
String valueMsg = String.format("Paths - %s", paths);
serviceImpl.sentRpcRequest(rpcRequest, CONTENT.name(), valueMsg, LOG_LW2M_VALUE);
}
}
@ -284,6 +299,7 @@ public class LwM2mTransportRequest {
private void sendRequest(Registration registration, LwM2mClient lwM2MClient, DownlinkRequest request,
long timeoutInMs, Lwm2mClientRpcRequest rpcRequest) {
context.getServer().send(registration, request, timeoutInMs, (ResponseCallback<?>) response -> {
if (!lwM2MClient.isInit()) {
lwM2MClient.initReadValue(this.serviceImpl, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration));
}
@ -301,25 +317,21 @@ public class LwM2mTransportRequest {
if (rpcRequest != null) {
serviceImpl.sentRpcRequest(rpcRequest, response.getCode().getName(), response.getErrorMessage(), LOG_LW2M_ERROR);
}
/* Not Found
set setClient_fw_version = empty
*/
if (FR_PATH_RESOURCE_VER_ID.equals(request.getPath().toString()) && lwM2MClient.isUpdateFw()) {
lwM2MClient.setUpdateFw(false);
lwM2MClient.getFrUpdate().setClientFwVersion("");
/** Not Found
set setClient_fw_info... = empty
**/
if (lwM2MClient.getFwUpdate().isInfoFwSwUpdate()) {
lwM2MClient.getFwUpdate().initReadValue(serviceImpl, request.getPath().toString());
log.warn("updateFirmwareClient1");
serviceImpl.updateFirmwareClient(lwM2MClient);
}
}
}, e -> {
/* version == null
set setClient_fw_version = empty
*/
if (FR_PATH_RESOURCE_VER_ID.equals(request.getPath().toString()) && lwM2MClient.isUpdateFw()) {
lwM2MClient.setUpdateFw(false);
lwM2MClient.getFrUpdate().setClientFwVersion("");
/** version == null
set setClient_fw_info... = empty
**/
if (lwM2MClient.getFwUpdate().isInfoFwSwUpdate()) {
lwM2MClient.getFwUpdate().initReadValue(serviceImpl, request.getPath().toString());
log.warn("updateFirmwareClient2");
serviceImpl.updateFirmwareClient(lwM2MClient);
}
if (!lwM2MClient.isInit()) {
lwM2MClient.initReadValue(this.serviceImpl, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration));
@ -458,21 +470,35 @@ public class LwM2mTransportRequest {
Math.min(valueLength, config.getLogMaxLength())));
}
value = valueLength > config.getLogMaxLength() ? value + "..." : value;
msg = String.format("%s: Update finished successfully: Lwm2m code - %d Resource path - %s length - %s value - %s",
msg = String.format("%s: Update finished successfully: Lwm2m code - %d Resource path: %s length: %s value: %s",
LOG_LW2M_INFO, response.getCode().getCode(), request.getPath().toString(), valueLength, value);
} else {
value = this.converter.convertValue(singleResource.getValue(),
singleResource.getType(), ResourceModel.Type.STRING, request.getPath());
msg = String.format("%s: Update finished successfully: Lwm2m code - %d Resource path - %s value - %s",
msg = String.format("%s: Update finished successfully. Lwm2m code: %d Resource path: %s value: %s",
LOG_LW2M_INFO, response.getCode().getCode(), request.getPath().toString(), value);
}
if (msg != null) {
serviceImpl.sendLogsToThingsboard(msg, registration.getId());
log.warn("[{}] [{}] [{}] - [{}] [{}] Update finished successfully: [{}]", request.getClass().getName(), registration.getEndpoint(),
((Response) response.getCoapResponse()).getCode(), response.getCode(), request.getPath().toString(), value);
log.warn(msg);
if (request.getPath().toString().equals(FW_PACKAGE_ID) || request.getPath().toString().equals(SW_PACKAGE_ID)) {
this.executeFwSwUpdate(registration, request);
}
}
} catch (Exception e) {
log.trace("Fail convert value from request to string. ", e);
}
}
private void executeFwSwUpdate(Registration registration, DownlinkRequest request) {
LwM2mClient lwM2mClient = this.lwM2mClientContext.getClientByRegistrationId(registration.getId());
if (request.getPath().toString().equals(FW_PACKAGE_ID)
&& FirmwareUpdateStatus.DOWNLOADING.name().equals(lwM2mClient.getFwUpdate().getStateUpdate())) {
lwM2mClient.getFwUpdate().sendReadInfoForWrite();
}
if (request.getPath().toString().equals(SW_PACKAGE_ID)
&& FirmwareUpdateStatus.DOWNLOADING.name().equals(lwM2mClient.getSwUpdate().getStateUpdate())) {
lwM2mClient.getSwUpdate().sendReadInfoForWrite();
}
}
}

View File

@ -43,6 +43,7 @@ import org.eclipse.leshan.server.registration.Registration;
import org.nustaq.serialization.FSTConfiguration;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration;
import org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.transport.TransportServiceCallback;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
@ -70,6 +71,12 @@ 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.firmware.FirmwareUpdateStatus.DOWNLOADED;
import static org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus.DOWNLOADING;
import static org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus.FAILED;
import static org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus.UPDATED;
import static org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus.UPDATING;
import static org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus.VERIFIED;
import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_KEY;
import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
@ -107,11 +114,41 @@ public class LwM2mTransportUtil {
public static final int LWM2M_STRATEGY_2 = 2;
public static final String CLIENT_NOT_AUTHORIZED = "Client not authorized";
public static final String LWM2M_VERSION_DEFAULT = "1.0";
public static final Integer FR_OBJECT_ID = 5;
public static final Integer FR_RESOURCE_VER_ID = 7;
public static final String FR_PATH_RESOURCE_VER_ID = LWM2M_SEPARATOR_PATH + FR_OBJECT_ID + LWM2M_SEPARATOR_PATH
+ "0" + LWM2M_SEPARATOR_PATH + FR_RESOURCE_VER_ID;
// FirmWare
public static final String FW_UPDATE = "Firmware update";
public static final Integer FW_ID = 5;
// Package W
public static final String FW_PACKAGE_ID = "/5/0/0";
// State R
public static final String FW_STATE_ID = "/5/0/3";
// Update Result R
public static final String FW_RESULT_ID = "/5/0/5";
// PkgName R
public static final String FW_NAME_ID = "/5/0/6";
// PkgVersion R
public static final String FW_VER_ID = "/5/0/7";
// Update E
public static final String FW_UPDATE_ID = "/5/0/2";
// SoftWare
public static final String SW_UPDATE = "Software update";
public static final Integer SW_ID = 9;
// Package W
public static final String SW_PACKAGE_ID = "/9/0/2";
// Update State R
public static final String SW_UPDATE_STATE_ID = "/9/0/7";
// Update Result R
public static final String SW_RESULT_ID = "/9/0/9";
// PkgName R
public static final String SW_NAME_ID = "/9/0/0";
// PkgVersion R
public static final String SW_VER_ID = "/9/0/1";
// Install E
public static final String SW_INSTALL_ID = "/9/0/4";
// Uninstall E
public static final String SW_UN_INSTALL_ID = "/9/0/6";
public enum LwM2mTypeServer {
BOOTSTRAP(0, "bootstrap"),
@ -144,19 +181,20 @@ public class LwM2mTransportUtil {
*/
READ(0, "Read"),
DISCOVER(1, "Discover"),
OBSERVE_READ_ALL(2, "ObserveReadAll"),
DISCOVER_All(2, "DiscoverAll"),
OBSERVE_READ_ALL(3, "ObserveReadAll"),
/**
* POST
*/
OBSERVE(3, "Observe"),
OBSERVE_CANCEL(4, "ObserveCancel"),
EXECUTE(5, "Execute"),
OBSERVE(4, "Observe"),
OBSERVE_CANCEL(5, "ObserveCancel"),
EXECUTE(6, "Execute"),
/**
* Replaces the Object Instance or the Resource(s) with the new value provided in the Write operation. (see
* section 5.3.3 of the LW M2M spec).
* if all resources are to be replaced
*/
WRITE_REPLACE(6, "WriteReplace"),
WRITE_REPLACE(7, "WriteReplace"),
/*
PUT
*/
@ -165,11 +203,13 @@ public class LwM2mTransportUtil {
* 5.3.3 of the LW M2M spec).
* if this is a partial update request
*/
WRITE_UPDATE(7, "WriteUpdate"),
WRITE_ATTRIBUTES(8, "WriteAttributes"),
DELETE(9, "Delete");
WRITE_UPDATE(8, "WriteUpdate"),
WRITE_ATTRIBUTES(9, "WriteAttributes"),
DELETE(10, "Delete"),
// READ_INFO_FW(10, "ReadInfoFirmware");
// only for RPC
READ_INFO_FW(11, "ReadInfoFirmware"),
READ_INFO_SW(12, "ReadInfoSoftware");
public int code;
public String type;
@ -189,10 +229,288 @@ public class LwM2mTransportUtil {
}
}
/**
* /** State R
* 0: Idle (before downloading or after successful updating)
* 1: Downloading (The data sequence is on the way)
* 2: Downloaded
* 3: Updating
*/
public enum StateFw {
IDLE(0, "Idle"),
DOWNLOADING(1, "Downloading"),
DOWNLOADED(2, "Downloaded"),
UPDATING(3, "Updating");
public int code;
public String type;
StateFw(int code, String type) {
this.code = code;
this.type = type;
}
public static StateFw fromStateFwByType(String type) {
for (StateFw to : StateFw.values()) {
if (to.type.equals(type)) {
return to;
}
}
throw new IllegalArgumentException(String.format("Unsupported FW State type : %s", type));
}
public static StateFw fromStateFwByCode(int code) {
for (StateFw to : StateFw.values()) {
if (to.code == code) {
return to;
}
}
throw new IllegalArgumentException(String.format("Unsupported FW State code : %s", code));
}
}
/**
* FW Update Result
* 0: Initial value. Once the updating process is initiated (Download /Update), this Resource MUST be reset to Initial value.
* 1: Firmware updated successfully.
* 2: Not enough flash memory for the new firmware package.
* 3: Out of RAM during downloading process.
* 4: Connection lost during downloading process.
* 5: Integrity check failure for new downloaded package.
* 6: Unsupported package type.
* 7: Invalid URI.
* 8: Firmware update failed.
* 9: Unsupported protocol.
*/
public enum UpdateResultFw {
INITIAL(0, "Initial value", false),
UPDATE_SUCCESSFULLY(1, "Firmware updated successfully", false),
NOT_ENOUGH(2, "Not enough flash memory for the new firmware package", false),
OUT_OFF_MEMORY(3, "Out of RAM during downloading process", false),
CONNECTION_LOST(4, "Connection lost during downloading process", true),
INTEGRITY_CHECK_FAILURE(5, "Integrity check failure for new downloaded package", true),
UNSUPPORTED_TYPE(6, "Unsupported package type", false),
INVALID_URI(7, "Invalid URI", false),
UPDATE_FAILED(8, "Firmware update failed", false),
UNSUPPORTED_PROTOCOL(9, "Unsupported protocol", false);
public int code;
public String type;
public boolean isAgain;
UpdateResultFw(int code, String type, boolean isAgain) {
this.code = code;
this.type = type;
this.isAgain = isAgain;
}
public static UpdateResultFw fromUpdateResultFwByType(String type) {
for (UpdateResultFw to : UpdateResultFw.values()) {
if (to.type.equals(type)) {
return to;
}
}
throw new IllegalArgumentException(String.format("Unsupported FW Update Result type : %s", type));
}
public static UpdateResultFw fromUpdateResultFwByCode(int code) {
for (UpdateResultFw to : UpdateResultFw.values()) {
if (to.code == code) {
return to;
}
}
throw new IllegalArgumentException(String.format("Unsupported FW Update Result code : %s", code));
}
}
/**
* FirmwareUpdateStatus {
* DOWNLOADING, DOWNLOADED, VERIFIED, UPDATING, UPDATED, FAILED
*/
public static FirmwareUpdateStatus EqualsFwSateToFirmwareUpdateStatus(StateFw stateFw, UpdateResultFw updateResultFw) {
switch (updateResultFw) {
case INITIAL:
switch (stateFw) {
case IDLE:
return VERIFIED;
case DOWNLOADING:
return DOWNLOADING;
case DOWNLOADED:
return DOWNLOADED;
case UPDATING:
return UPDATING;
}
case UPDATE_SUCCESSFULLY:
return UPDATED;
case NOT_ENOUGH:
case OUT_OFF_MEMORY:
case CONNECTION_LOST:
case INTEGRITY_CHECK_FAILURE:
case UNSUPPORTED_TYPE:
case INVALID_URI:
case UPDATE_FAILED:
case UNSUPPORTED_PROTOCOL:
return FAILED;
default:
throw new CodecException("Invalid value stateFw %s %s for FirmwareUpdateStatus.", stateFw.name(), updateResultFw.name());
}
}
/**
* Update State R
* 0: INITIAL Before downloading. (see 5.1.2.1)
* 1: DOWNLOAD STARTED The downloading process has started and is on-going. (see 5.1.2.2)
* 2: DOWNLOADED The package has been completely downloaded (see 5.1.2.3)
* 3: DELIVERED In that state, the package has been correctly downloaded and is ready to be installed. (see 5.1.2.4)
* If executing the Install Resource failed, the state remains at DELIVERED.
* If executing the Install Resource was successful, the state changes from DELIVERED to INSTALLED.
* After executing the UnInstall Resource, the state changes to INITIAL.
* 4: INSTALLED
*/
public enum UpdateStateSw {
INITIAL(0, "Initial"),
DOWNLOAD_STARTED(1, "DownloadStarted"),
DOWNLOADED(2, "Downloaded"),
DELIVERED(3, "Delivered"),
INSTALLED(4, "Installed");
public int code;
public String type;
UpdateStateSw(int code, String type) {
this.code = code;
this.type = type;
}
public static UpdateStateSw fromUpdateStateSwByType(String type) {
for (UpdateStateSw to : UpdateStateSw.values()) {
if (to.type.equals(type)) {
return to;
}
}
throw new IllegalArgumentException(String.format("Unsupported SW State type : %s", type));
}
public static UpdateStateSw fromUpdateStateSwByCode(int code) {
for (UpdateStateSw to : UpdateStateSw.values()) {
if (to.code == code) {
return to;
}
}
throw new IllegalArgumentException(String.format("Unsupported SW State type : %s", code));
}
}
/**
* SW Update Result
* Contains the result of downloading or installing/uninstalling the software
* 0: Initial value.
* - Prior to download any new package in the Device, Update Result MUST be reset to this initial value.
* - One side effect of executing the Uninstall resource is to reset Update Result to this initial value "0".
* 1: Downloading.
* - The package downloading process is on-going.
* 2: Software successfully installed.
* 3: Successfully Downloaded and package integrity verified
* (( 4-49, for expansion, of other scenarios))
* ** Failed
* 50: Not enough storage for the new software package.
* 51: Out of memory during downloading process.
* 52: Connection lost during downloading process.
* 53: Package integrity check failure.
* 54: Unsupported package type.
* 56: Invalid URI
* 57: Device defined update error
* 58: Software installation failure
* 59: Uninstallation Failure during forUpdate(arg=0)
* 60-200 : (for expansion, selection to be in blocks depending on new introduction of features)
* This Resource MAY be reported by sending Observe operation.
*/
public enum UpdateResultSw {
INITIAL(0, "Initial value", false),
DOWNLOADING(1, "Downloading", false),
SUCCESSFULLY_INSTALLED(2, "Software successfully installed", false),
SUCCESSFULLY_INSTALLED_VERIFIED(3, "Successfully Downloaded and package integrity verified", false),
NOT_ENOUGH_STORAGE(50, "Not enough storage for the new software package", true),
OUT_OFF_MEMORY(51, "Out of memory during downloading process", true),
CONNECTION_LOST(52, "Connection lost during downloading process", false),
PACKAGE_CHECK_FAILURE(53, "Package integrity check failure.", false),
UNSUPPORTED_PACKAGE_TYPE(54, "Unsupported package type", false),
INVALID_URI(56, "Invalid URI", true),
UPDATE_ERROR(57, "Device defined update error", true),
INSTALL_FAILURE(58, "Software installation failure", true),
UN_INSTALL_FAILURE(59, "Uninstallation Failure during forUpdate(arg=0)", true);
public int code;
public String type;
public boolean isAgain;
UpdateResultSw(int code, String type, boolean isAgain) {
this.code = code;
this.type = type;
this.isAgain = isAgain;
}
public static UpdateResultSw fromUpdateResultSwByType(String type) {
for (UpdateResultSw to : UpdateResultSw.values()) {
if (to.type.equals(type)) {
return to;
}
}
throw new IllegalArgumentException(String.format("Unsupported SW Update Result type : %s", type));
}
public static UpdateResultSw fromUpdateResultSwByCode(int code) {
for (UpdateResultSw to : UpdateResultSw.values()) {
if (to.code == code) {
return to;
}
}
throw new IllegalArgumentException(String.format("Unsupported SW Update Result code : %s", code));
}
}
/**
* FirmwareUpdateStatus {
* DOWNLOADING, DOWNLOADED, VERIFIED, UPDATING, UPDATED, FAILED
*/
public static FirmwareUpdateStatus EqualsSwSateToFirmwareUpdateStatus(UpdateStateSw updateStateSw, UpdateResultSw updateResultSw) {
switch (updateResultSw) {
case INITIAL:
switch (updateStateSw) {
case INITIAL:
case DOWNLOAD_STARTED:
return DOWNLOADING;
case DOWNLOADED:
return DOWNLOADED;
case DELIVERED:
return VERIFIED;
}
case DOWNLOADING:
return DOWNLOADING;
case SUCCESSFULLY_INSTALLED:
return UPDATED;
case SUCCESSFULLY_INSTALLED_VERIFIED:
return VERIFIED;
case NOT_ENOUGH_STORAGE:
case OUT_OFF_MEMORY:
case CONNECTION_LOST:
case PACKAGE_CHECK_FAILURE:
case UNSUPPORTED_PACKAGE_TYPE:
case INVALID_URI:
case UPDATE_ERROR:
case INSTALL_FAILURE:
case UN_INSTALL_FAILURE:
return FAILED;
default:
throw new CodecException("Invalid value stateFw %s %s for FirmwareUpdateStatus.", updateStateSw.name(), updateResultSw.name());
}
}
public static final String EVENT_AWAKE = "AWAKE";
public static final String RESPONSE_CHANNEL = "RESP";
public static boolean equalsResourceValue(Object valueOld, Object valueNew, ResourceModel.Type type, LwM2mPath resourcePath) throws CodecException {
public static boolean equalsResourceValue(Object valueOld, Object valueNew, ResourceModel.Type type, LwM2mPath
resourcePath) throws CodecException {
switch (type) {
case BOOLEAN:
case INTEGER:
@ -256,7 +574,7 @@ public class LwM2mTransportUtil {
* "/3_1.0/0/9": {"pmax": 45}, "/3_1.2": {ver": "3_1.2"}}
*/
public static LwM2mClientProfile toLwM2MClientProfile(DeviceProfile deviceProfile) {
if (deviceProfile != null && ((Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration()).getProperties().size() > 0) {
if (((Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration()).getProperties().size() > 0) {
Object profile = ((Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration()).getProperties();
try {
ObjectMapper mapper = new ObjectMapper();
@ -375,7 +693,8 @@ public class LwM2mTransportUtil {
return StringUtils.join(linkedListOut, "");
}
public static <T> TransportServiceCallback<Void> getAckCallback(LwM2mClient lwM2MClient, int requestId, String typeTopic) {
public static <T> TransportServiceCallback<Void> getAckCallback(LwM2mClient lwM2MClient,
int requestId, String typeTopic) {
return new TransportServiceCallback<Void>() {
@Override
public void onSuccess(Void dummy) {
@ -420,7 +739,8 @@ public class LwM2mTransportUtil {
return null;
}
public static String validPathIdVer(String pathIdVer, Registration registration) throws IllegalArgumentException {
public static String validPathIdVer(String pathIdVer, Registration registration) throws
IllegalArgumentException {
if (!pathIdVer.contains(LWM2M_SEPARATOR_PATH)) {
throw new IllegalArgumentException(String.format("Error:"));
} else {
@ -436,6 +756,7 @@ public class LwM2mTransportUtil {
public static String convertPathFromObjectIdToIdVer(String path, Registration registration) {
String ver = registration.getSupportedObject().get(new LwM2mPath(path).getObjectId());
ver = ver != null ? ver : LWM2M_VERSION_DEFAULT;
try {
String[] keyArray = path.split(LWM2M_SEPARATOR_PATH);
if (keyArray.length > 1) {
@ -531,7 +852,7 @@ public class LwM2mTransportUtil {
case "ObjectLink":
return OBJLNK;
default:
return null;
return null;
}
}
}

View File

@ -27,6 +27,7 @@ import org.eclipse.leshan.server.registration.Registration;
import org.eclipse.leshan.server.security.SecurityInfo;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.firmware.FirmwareType;
import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto;
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg;
@ -49,8 +50,9 @@ import java.util.stream.Collectors;
import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
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.getVerFromPathIdVerOrId;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.equalsResourceTypeGetSimpleName;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getVerFromPathIdVerOrId;
@Slf4j
public class LwM2mClient implements Cloneable {
@ -74,25 +76,25 @@ public class LwM2mClient implements Cloneable {
private UUID profileId;
@Getter
@Setter
private volatile LwM2mFirmwareUpdate frUpdate;
private volatile LwM2mFwSwUpdate fwUpdate;
@Getter
@Setter
private volatile LwM2mFwSwUpdate swUpdate;
@Getter
@Setter
private Registration registration;
private ValidateDeviceCredentialsResponseMsg credentialsResponse;
@Getter
private final Map<String, ResourceValue> resources;
@Getter
private final Map<String, TsKvProto> delayedRequests;
@Getter
@Setter
private final List<String> pendingReadRequests;
@Getter
private final Queue<LwM2mQueuedRequest> queuedRequests;
@Getter
private boolean init;
@Getter
@Setter
private volatile boolean updateFw;
public Object clone() throws CloneNotSupportedException {
return super.clone();
@ -109,9 +111,9 @@ public class LwM2mClient implements Cloneable {
this.profileId = profileId;
this.sessionId = sessionId;
this.init = false;
this.updateFw = false;
this.queuedRequests = new ConcurrentLinkedQueue<>();
this.frUpdate = new LwM2mFirmwareUpdate();
this.fwUpdate = new LwM2mFwSwUpdate(this, FirmwareType.FIRMWARE);
this.swUpdate = new LwM2mFwSwUpdate(this, FirmwareType.SOFTWARE);
if (this.credentialsResponse != null && this.credentialsResponse.hasDeviceInfo()) {
this.session = createSession(nodeId, sessionId, credentialsResponse);
this.deviceId = new UUID(session.getDeviceIdMSB(), session.getDeviceIdLSB());
@ -164,15 +166,15 @@ public class LwM2mClient implements Cloneable {
.build();
}
public boolean saveResourceValue(String pathRez, LwM2mResource rez, LwM2mModelProvider modelProvider) {
if (this.resources.get(pathRez) != null && this.resources.get(pathRez).getResourceModel() != null) {
this.resources.get(pathRez).setLwM2mResource(rez);
public boolean saveResourceValue(String pathRezIdVer, LwM2mResource rez, LwM2mModelProvider modelProvider) {
if (this.resources.get(pathRezIdVer) != null && this.resources.get(pathRezIdVer).getResourceModel() != null) {
this.resources.get(pathRezIdVer).setLwM2mResource(rez);
return true;
} else {
LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRez));
LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRezIdVer));
ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId());
if (resourceModel != null) {
this.resources.put(pathRez, new ResourceValue(rez, resourceModel));
this.resources.put(pathRezIdVer, new ResourceValue(rez, resourceModel));
return true;
} else {
return false;
@ -180,6 +182,16 @@ public class LwM2mClient implements Cloneable {
}
}
public Object getResourceValue (String pathRezIdVer, String pathRezId) {
String pathRez = pathRezIdVer == null ? convertPathFromObjectIdToIdVer(pathRezId, this.registration) : pathRezIdVer;
if (this.resources.get(pathRez) != null) {
return this.resources.get(pathRez).getLwM2mResource().isMultiInstances() ?
this.resources.get(pathRez).getLwM2mResource().getValues() :
this.resources.get(pathRez).getLwM2mResource().getValue();
}
return null;
}
public ResourceModel getResourceModel(String pathIdVer, LwM2mModelProvider modelProvider) {
LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer));
String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId());

View File

@ -54,7 +54,7 @@ public interface LwM2mClientContext {
Map<UUID, LwM2mClientProfile> setProfiles(Map<UUID, LwM2mClientProfile> profiles);
LwM2mClientProfile toClientProfile(DeviceProfile deviceProfile);
LwM2mClientProfile profileUpdate(DeviceProfile deviceProfile);
Set<String> getSupportedIdVerInClient(Registration registration);

View File

@ -16,6 +16,7 @@
package org.thingsboard.server.transport.lwm2m.server.client;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.core.node.LwM2mPath;
import org.eclipse.leshan.server.registration.Registration;
import org.eclipse.leshan.server.security.EditableSecurityStore;
@ -40,6 +41,7 @@ import java.util.concurrent.ConcurrentHashMap;
import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.NO_SEC;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer;
@Slf4j
@Service
@TbLwM2mTransportComponent
@RequiredArgsConstructor
@ -112,8 +114,12 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
EndpointSecurityInfo securityInfo = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfo(endpoint, LwM2mTransportUtil.LwM2mTypeServer.CLIENT);
if (securityInfo.getSecurityMode() < LwM2MSecurityMode.DEFAULT_MODE.code) {
if (securityInfo.getDeviceProfile() != null) {
toClientProfile(securityInfo.getDeviceProfile());
UUID profileUuid = securityInfo.getDeviceProfile().getUuidId();
UUID profileUuid = profileUpdate(securityInfo.getDeviceProfile())!= null ?
securityInfo.getDeviceProfile().getUuidId() : null;
// TODO: for tests bug.
if (profileUuid== null) {
log.warn("input parameters toClientProfile if the result is null: [{}]", securityInfo.getDeviceProfile());
}
LwM2mClient client;
if (securityInfo.getSecurityInfo() != null) {
client = new LwM2mClient(context.getNodeId(), securityInfo.getSecurityInfo().getEndpoint(),
@ -162,13 +168,16 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
}
@Override
public LwM2mClientProfile toClientProfile(DeviceProfile deviceProfile) {
LwM2mClientProfile lwM2MClientProfile = profiles.get(deviceProfile.getUuidId());
if (lwM2MClientProfile == null) {
lwM2MClientProfile = LwM2mTransportUtil.toLwM2MClientProfile(deviceProfile);
public LwM2mClientProfile profileUpdate(DeviceProfile deviceProfile) {
LwM2mClientProfile lwM2MClientProfile = deviceProfile != null ?
LwM2mTransportUtil.toLwM2MClientProfile(deviceProfile) : null;
if (lwM2MClientProfile != null) {
profiles.put(deviceProfile.getUuidId(), lwM2MClientProfile);
return lwM2MClientProfile;
}
else {
return null;
}
return lwM2MClientProfile;
}
/**

View File

@ -1,27 +0,0 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.server.client;
import lombok.Data;
import java.util.UUID;
@Data
public class LwM2mFirmwareUpdate {
private volatile String clientFwVersion;
private volatile String currentFwVersion;
private volatile UUID currentFwId;
}

View File

@ -0,0 +1,333 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.server.client;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.leshan.core.request.ContentFormat;
import org.thingsboard.server.common.data.firmware.FirmwareType;
import org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.transport.lwm2m.server.DefaultLwM2MTransportMsgHandler;
import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;
import static org.thingsboard.server.common.data.firmware.FirmwareKey.STATE;
import static org.thingsboard.server.common.data.firmware.FirmwareType.FIRMWARE;
import static org.thingsboard.server.common.data.firmware.FirmwareType.SOFTWARE;
import static org.thingsboard.server.common.data.firmware.FirmwareUtil.getAttributeKey;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_NAME_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_PACKAGE_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_RESULT_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_STATE_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_UPDATE;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_UPDATE_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_VER_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_INFO;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.EXECUTE;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.READ;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_REPLACE;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_INSTALL_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_NAME_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_PACKAGE_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_RESULT_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_UN_INSTALL_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_UPDATE;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_UPDATE_STATE_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_VER_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer;
@Slf4j
public class LwM2mFwSwUpdate {
// 5/0/6 PkgName
// 9/0/0 PkgName
@Getter
@Setter
private volatile String currentTitle;
// 5/0/7 PkgVersion
// 9/0/1 PkgVersion
@Getter
@Setter
private volatile String currentVersion;
@Getter
@Setter
private volatile UUID currentId;
@Getter
@Setter
private volatile String stateUpdate;
@Getter
private String pathPackageId;
@Getter
private String pathStateId;
@Getter
private String pathResultId;
@Getter
private String pathNameId;
@Getter
private String pathVerId;
@Getter
private String pathInstallId;
@Getter
private String pathUnInstallId;
@Getter
private String wUpdate;
@Getter
@Setter
private volatile boolean infoFwSwUpdate = false;
private final FirmwareType type;
private DefaultLwM2MTransportMsgHandler serviceImpl;
@Getter
LwM2mClient lwM2MClient;
@Getter
@Setter
private final List<String> pendingInfoRequestsStart;
public LwM2mFwSwUpdate(LwM2mClient lwM2MClient, FirmwareType type) {
this.lwM2MClient = lwM2MClient;
this.pendingInfoRequestsStart = new CopyOnWriteArrayList<>();
this.type = type;
this.stateUpdate = null;
this.initPathId();
}
private void initPathId() {
if (this.type.equals(FIRMWARE)) {
this.pathPackageId = FW_PACKAGE_ID;
this.pathStateId = FW_STATE_ID;
this.pathResultId = FW_RESULT_ID;
this.pathNameId = FW_NAME_ID;
this.pathVerId = FW_VER_ID;
this.pathInstallId = FW_UPDATE_ID;
this.wUpdate = FW_UPDATE;
} else if (this.type.equals(SOFTWARE)) {
this.pathPackageId = SW_PACKAGE_ID;
this.pathStateId = SW_UPDATE_STATE_ID;
this.pathResultId = SW_RESULT_ID;
this.pathNameId = SW_NAME_ID;
this.pathVerId = SW_VER_ID;
this.pathInstallId = SW_INSTALL_ID;
this.pathUnInstallId = SW_UN_INSTALL_ID;
this.wUpdate = SW_UPDATE;
}
}
public void initReadValue(DefaultLwM2MTransportMsgHandler serviceImpl, String pathIdVer) {
if (this.serviceImpl == null) this.serviceImpl = serviceImpl;
if (pathIdVer != null) {
this.pendingInfoRequestsStart.remove(pathIdVer);
}
if (this.pendingInfoRequestsStart.size() == 0) {
this.infoFwSwUpdate = false;
if (!FirmwareUpdateStatus.DOWNLOADING.name().equals(this.stateUpdate)) {
boolean conditionalStart = this.type.equals(FIRMWARE) ? this.conditionalFwUpdateStart() :
this.conditionalSwUpdateStart();
if (conditionalStart) {
this.stateUpdate = FirmwareUpdateStatus.DOWNLOADING.name();
this.observeStateUpdate();
this.writeFwSwWare();
this.sendLogs(WRITE_REPLACE.name());
}
} else {
boolean conditionalExecute = this.type.equals(FIRMWARE) ? conditionalFwUpdateExecute() :
conditionalSwUpdateExecute();
if (conditionalExecute) {
this.stateUpdate = FirmwareUpdateStatus.DOWNLOADED.name();
this.observeStateUpdate();
this.executeFwSwWare();
this.sendLogs(EXECUTE.name());
}
}
}
}
private void writeFwSwWare() {
int chunkSize = 0;
int chunk = 0;
byte[] firmwareChunk = this.serviceImpl.firmwareDataCache.get(this.currentId.toString(), chunkSize, chunk);
String targetIdVer = convertPathFromObjectIdToIdVer(this.pathPackageId, this.lwM2MClient.getRegistration());
this.serviceImpl.lwM2mTransportRequest.sendAllRequest(lwM2MClient.getRegistration(), targetIdVer, WRITE_REPLACE, ContentFormat.OPAQUE.getName(),
firmwareChunk, this.serviceImpl.config.getTimeout(), null);
}
public void sendLogs(String typeOper) {
this.sendSateOnThingsboard();
String msg = String.format("%s: %s, %s, pkgVer: %s: pkgName - %s.",
LOG_LW2M_INFO, this.wUpdate, typeOper, this.currentVersion, this.currentTitle);
serviceImpl.sendLogsToThingsboard(msg, lwM2MClient.getRegistration().getId());
log.warn("{} state: [{}]", msg, this.stateUpdate);
}
public void executeFwSwWare() {
this.serviceImpl.lwM2mTransportRequest.sendAllRequest(this.lwM2MClient.getRegistration(), this.pathInstallId, EXECUTE, ContentFormat.TLV.getName(),
null, 0, null);
}
/**
* FW: start
* Проверяем состояние State (5.3) и Update Result (5.5).
* 1. Если Update Result > 1 (some errors) - Это означает что пред. апдейт не прошел.
* - Запускаем апдейт в независимости от состяния прошивки и ее версии.
* 2. Если Update Result = 1 && State = 0 - Это означает что пред. апдейт прошел.
* 3. Если Update Result = 0 && State = 0 && Ver = "" - Это означает что апдейта еще не было.
* - Проверяем поменялась ли версия и запускаем новый апдейт.
* Новый апдейт:
* 1. Запись новой прошивки в Lwm2mClient
* 2. Мониторим итог зиписи:
* 2.1 State = 2 "Downloaded" и Update Result = 0 "INITIAL" стартуем Update 5.2 (Execute):
* Мониторим состояние Update Result и State и мапим его на наш enum (DOWNLOADING, DOWNLOADED, VERIFIED, UPDATING, UPDATED, FAILED)
* + пишем лог (в телеметрию отдельным полем error) с подробным статусом.
*
* @valerii.sosliuk Вопрос к клиенту - как будем реагировать на Failed update? Когда повторять операцию?
* - На update reg?
* - Или клиент должен послать комканду на рестарт девайса?
* - или переодически?
* отправили прошивку мониторим:
* -- Observe "Update Result" id=5 && "State" id=3
* --- "Update Result" id=5 value must be = 0
* --- "State" id=3 value must be > 0
* --- to telemetry - DOWNLOADING
* "Update Result" id=5 value change > 1 "Firmware updated not successfully" отправили прошивку: telemetry - FAILED
* "Update Result" id=5 value change ==1 "State" id=3 value == 0 "Firmware updated successfully" отправили прошивку: telemetry - UPDATED
*/
private boolean conditionalFwUpdateStart() {
Long stateFw = (Long) this.lwM2MClient.getResourceValue(null, this.pathStateId);
Long updateResultFw = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId);
String pkgName = (String) this.lwM2MClient.getResourceValue(null, this.pathNameId);
// #1/#2
return updateResultFw > LwM2mTransportUtil.UpdateResultFw.UPDATE_SUCCESSFULLY.code ||
(
(
(stateFw == LwM2mTransportUtil.StateFw.IDLE.code && updateResultFw == LwM2mTransportUtil.UpdateResultFw.UPDATE_SUCCESSFULLY.code) ||
(stateFw == LwM2mTransportUtil.StateFw.IDLE.code && updateResultFw == LwM2mTransportUtil.UpdateResultFw.INITIAL.code
&& StringUtils.trimToEmpty(pkgName).isEmpty())
) &&
(
(this.currentVersion != null && !this.currentVersion.equals(this.lwM2MClient.getResourceValue(null, this.pathVerId))) ||
(this.currentTitle != null && !this.currentTitle.equals(this.lwM2MClient.getResourceValue(null, this.pathNameId)))
)
);
// if (condFwUpdateStart) {
// this.sendSateOnThingsboard(stateFw, updateResultFw, pkgName);
// }
// return condFwUpdateStart;
}
private boolean conditionalFwUpdateExecute() {
Long state = (Long) this.lwM2MClient.getResourceValue(null, this.pathStateId);
Long updateResult = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId);
// #1/#2
return updateResult == LwM2mTransportUtil.UpdateResultFw.INITIAL.code && state == LwM2mTransportUtil.StateFw.DOWNLOADED.code;
}
/**
* FW: start
* Проверяем состояние Update_State (9.7) и Update_Result (9.9).
* 1. Если Update Result > 3 (some errors) - Это означает что пред. апдейт не прошел.
* - Запускаем апдейт в независимости от состяния прошивки и ее версии.
* 2. Если Update Result = 2 && Update State = 4 - Это означает что пред. апдейт прошел
* 3. Если Update Result = 0 && Update State = 0 && Ver = "" - Это означает что апдейта еще не было.
* 4. Если Update Result = 0 && Update State = 0 - Это означает что пред. апдейт UnInstall
* - Проверяем поменялась ли версия и запускаем новый апдейт.
* Новый апдейт:
* 1. Запись новой прошивки в Lwm2mClient
* 2. Мониторим итог зиписи:
* 2.1 Update State = 3 "DELIVERED" стартуем Install 9.4 (Execute):
* Мониторим состояние Update Result и State и мапим его на наш enum (DOWNLOADING, DOWNLOADED, VERIFIED, UPDATING, UPDATED, FAILED)
* + пишем лог (в телеметрию отдельным полем error) с подробным статусом.
*/
private boolean conditionalSwUpdateStart() {
Long updateState = (Long) this.lwM2MClient.getResourceValue(null, this.pathStateId);
Long updateResult = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId);
String pkgName = (String) this.lwM2MClient.getResourceValue(null, this.pathNameId);
// #1/#2
return updateResult > LwM2mTransportUtil.UpdateResultSw.SUCCESSFULLY_INSTALLED_VERIFIED.code ||
(
(
(
(
(updateState == LwM2mTransportUtil.UpdateStateSw.INSTALLED.code && updateResult == LwM2mTransportUtil.UpdateResultSw.SUCCESSFULLY_INSTALLED.code) ||
(updateState == LwM2mTransportUtil.UpdateStateSw.INITIAL.code && updateResult == LwM2mTransportUtil.UpdateResultSw.INITIAL.code &&
StringUtils.trimToEmpty(pkgName).isEmpty())
)
) &&
(updateState == LwM2mTransportUtil.UpdateStateSw.INITIAL.code && updateResult == LwM2mTransportUtil.UpdateResultSw.INITIAL.code)
) &&
(
(this.currentVersion != null && !this.currentVersion.equals(this.lwM2MClient.getResourceValue(null, this.pathVerId))) ||
(this.currentTitle != null && !this.currentTitle.equals(this.lwM2MClient.getResourceValue(null, this.pathNameId)))
)
);
// return condSwUpdateStart;
}
private boolean conditionalSwUpdateExecute() {
Long updateState = (Long) this.lwM2MClient.getResourceValue(null, this.pathStateId);
Long updateResult = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId);
// #1/#2
return (updateResult == LwM2mTransportUtil.UpdateResultSw.INITIAL.code || updateResult == LwM2mTransportUtil.UpdateResultSw.SUCCESSFULLY_INSTALLED_VERIFIED.code) &&
updateState == LwM2mTransportUtil.UpdateStateSw.DELIVERED.code;
}
private void observeStateUpdate() {
this.serviceImpl.lwM2mTransportRequest.sendAllRequest(lwM2MClient.getRegistration(),
convertPathFromObjectIdToIdVer(this.pathStateId, this.lwM2MClient.getRegistration()), OBSERVE,
null, null, 0, null);
this.serviceImpl.lwM2mTransportRequest.sendAllRequest(lwM2MClient.getRegistration(),
convertPathFromObjectIdToIdVer(this.pathResultId, this.lwM2MClient.getRegistration()), OBSERVE,
null, null, 0, null);
}
public void sendSateOnThingsboard() {
if (StringUtils.trimToNull(this.stateUpdate) != null) {
List<TransportProtos.KeyValueProto> result = new ArrayList<>();
TransportProtos.KeyValueProto.Builder kvProto = TransportProtos.KeyValueProto.newBuilder().setKey(getAttributeKey(this.type, STATE));
kvProto.setType(TransportProtos.KeyValueType.STRING_V).setStringV(stateUpdate);
result.add(kvProto.build());
this.serviceImpl.helper.sendParametersOnThingsboardTelemetry(result,
this.serviceImpl.getSessionInfoOrCloseSession(this.lwM2MClient.getRegistration()));
}
}
public void sendReadInfo(DefaultLwM2MTransportMsgHandler serviceImpl) {
this.serviceImpl = this.serviceImpl == null ? serviceImpl : this.serviceImpl;
this.pendingInfoRequestsStart.add(convertPathFromObjectIdToIdVer(
this.pathVerId, this.lwM2MClient.getRegistration()));
this.pendingInfoRequestsStart.add(convertPathFromObjectIdToIdVer(
this.pathNameId, this.lwM2MClient.getRegistration()));
this.sendReadInfoForWrite();
}
public void sendReadInfoForWrite() {
this.infoFwSwUpdate = true;
this.pendingInfoRequestsStart.add(convertPathFromObjectIdToIdVer(
this.pathStateId, this.lwM2MClient.getRegistration()));
this.pendingInfoRequestsStart.add(convertPathFromObjectIdToIdVer(
this.pathResultId, this.lwM2MClient.getRegistration()));
this.pendingInfoRequestsStart.forEach(pathIdVer -> {
this.serviceImpl.lwM2mTransportRequest.sendAllRequest(this.lwM2MClient.getRegistration(), pathIdVer, READ, ContentFormat.TLV.getName(),
null, 0, null);
});
}
}

View File

@ -17,6 +17,7 @@ package org.thingsboard.server.transport.lwm2m.server.client;
import com.google.gson.JsonObject;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.core.request.ContentFormat;
import org.eclipse.leshan.server.registration.Registration;
import org.thingsboard.server.gen.transport.TransportProtos;
@ -27,6 +28,7 @@ import java.util.concurrent.ConcurrentHashMap;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.validPathIdVer;
@Slf4j
@Data
public class Lwm2mClientRpcRequest {
public final String targetIdVerKey = "targetIdVer";
@ -113,7 +115,7 @@ public class Lwm2mClientRpcRequest {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
log.error("", e);
}
return null;
}