Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Including timestamped send option to SendService #1584

Closed
Ozame opened this issue Feb 9, 2024 · 3 comments
Closed

Including timestamped send option to SendService #1584

Ozame opened this issue Feb 9, 2024 · 3 comments
Labels
question Any question about leshan

Comments

@Ozame
Copy link

Ozame commented Feb 9, 2024

Question

Currently the default LeshanClient creates an implementation of SendService that can be used to send data from the client to the server. This implementation contains both the sync and async versions of the send. However, DataSenderManager used to send the data also supports the versions of sendData that take TimestampedNodes instead of plain LwM2mNodes:

public SendResponse sendData(LwM2mServer server, ContentFormat format, TimestampedLwM2mNodes nodes,
            long timeoutInMs)

vs.

public SendResponse sendData(LwM2mServer server, ContentFormat format, Map<LwM2mPath, LwM2mNode> nodes,
            long timeoutInMs)

Would it make sense to include this timestamped option to the default client / SendService interface? Or would this be unnecessary bloat for most users? Currently, if the timestamps are needed, a custom client class, or at least a clientBuilder class, is needed.

Changes would be needed to SendService interface and the LeshanClient for this. Implementation itself is trivial, e.g.

 public SendResponse sendTimeStampedData(LwM2mServer server, ContentFormat format, List<String> paths, long timeoutInMs) throws InterruptedException {
                Validate.notNull(server);
                Validate.notEmpty(paths);
                Map<LwM2mPath, LwM2mNode> collectedData = Client.this.dataSenderManager.getCurrentValues(server, LwM2mPath.getLwM2mPathList(paths));
                var now = Instant.now();
                TimestampedLwM2mNodes nodes = TimestampedLwM2mNodes.builder()
                        .addNodes(now, collectedData)
                        .build();
                return Client.this.dataSenderManager.sendData(server, format, nodes, timeoutInMs);
            }

Depending of course if we want the timestamp to be passed or automatically created.

This case comes up when we use the LWM2M send service to push event related measurements from the client. I'm not sure if it's a common use case or not.

If this sounds good, I could submit a PR for this.

@Ozame Ozame added the question Any question about leshan label Feb 9, 2024
@sbernard31
Copy link
Contributor

Iam not sure but maybeManualDataSender is what need ?

Do you test the it ? it is able to collect timestamped data then send all collected data ?

You can test its behavior with leshan-client-demo ? using this interactive command

help collect

Usage:  collect [<paths>...]
Collect data to send it later with 'send' command
      [<paths>...]   Paths of data to collect.

help send

Usage:  send [-c=<contentFormat>] (current-value | collected-value)
Send data to server
  -c, --content-format=<contentFormat>
         Name (e.g. SENML_JSON) or code (e.g. 110) of Content Format used to
           send data.
         Default : SENML_CBOR
Commands:
  current-value    Send current value
  collected-value  Send values collected with 'collect' command

You could have code example here :

/**
* A command to collect data.
*/
@Command(name = "collect",
description = "Collect data to send it later with 'send' command",
headerHeading = "%n",
footer = "")
static class CollectCommand implements Runnable {
@Parameters(description = "Paths of data to collect.", converter = LwM2mPathConverter.class)
private List<LwM2mPath> paths;
@ParentCommand
InteractiveCommands parent;
@Override
public void run() {
parent.client.getSendService().getDataSender(ManualDataSender.DEFAULT_NAME, ManualDataSender.class)
.collectData(paths);
}
}

and

@Command(name = "collected-value",
description = "Send values collected with 'collect' command",
headerHeading = "%n",
footer = "")
static class SendCollectedValue implements Runnable {
@ParentCommand
SendCommand sendCommand;
@Override
public void run() {
// get registered servers
Map<String, LwM2mServer> registeredServers = sendCommand.parent.client.getRegisteredServers();
if (registeredServers.isEmpty()) {
sendCommand.parent.printf("There is no registered server to send to.%n").flush();
}
// for each server send data
for (final LwM2mServer server : registeredServers.values()) {
LOG.info("Sending Collected data to {} using {}.", server, sendCommand.contentFormat);
// send collected data
SendService sendService = sendCommand.parent.client.getSendService();
try {
sendService.getDataSender(ManualDataSender.DEFAULT_NAME, ManualDataSender.class)
.sendCollectedData(server, sendCommand.contentFormat, sendCommand.timeout, false);
} catch (NoDataException e) {
sendCommand.parent.printf("No data collected, use `collect` command before.%n").flush();
}
}
}
}

If this doesn't match you need, could you try to explain why ? 🙏

@sbernard31
Copy link
Contributor

Does that work for you ? should we close this issue ?

@Ozame
Copy link
Author

Ozame commented Mar 4, 2024

Yes, this actually looks to be exactly what we needed, thank you! I will close the issue.

@Ozame Ozame closed this as completed Mar 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Any question about leshan
Projects
None yet
Development

No branches or pull requests

2 participants