Skip to content

Commit

Permalink
servicetests/tests/ShadowUpdate/CMakeLists.txt servicetests/tests/Sha…
Browse files Browse the repository at this point in the history
…dowUpdate/main.cpp
  • Loading branch information
alfred2g committed Dec 2, 2023
1 parent b7f01b4 commit e7e3e41
Show file tree
Hide file tree
Showing 2 changed files with 319 additions and 0 deletions.
28 changes: 28 additions & 0 deletions servicetests/tests/ShadowUpdate/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
cmake_minimum_required(VERSION 3.1)
# note: cxx-17 requires cmake 3.8, cxx-20 requires cmake 3.12
project(shadow-update CXX)

file(GLOB SRC_FILES
"*.cpp"
"../../../samples/utils/CommandLineUtils.cpp"
"../../../samples/utils/CommandLineUtils.h"
)

add_executable(${PROJECT_NAME} ${SRC_FILES})

set_target_properties(${PROJECT_NAME} PROPERTIES
CXX_STANDARD 14)

#set warnings
if (MSVC)
target_compile_options(${PROJECT_NAME} PRIVATE /W4 /WX)
else ()
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wno-long-long -pedantic -Werror)
endif ()

find_package(aws-crt-cpp REQUIRED)
find_package(IotShadow-cpp REQUIRED)

install(TARGETS ${PROJECT_NAME} DESTINATION bin)

target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp AWS::IotShadow-cpp)
291 changes: 291 additions & 0 deletions servicetests/tests/ShadowUpdate/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,291 @@
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#include <aws/crt/Api.h>
#include <aws/crt/JsonObject.h>
#include <aws/crt/UUID.h>
#include <aws/crt/io/HostResolver.h>

#include <aws/crt/mqtt/Mqtt5Packets.h>
#include <aws/iot/Mqtt5Client.h>
#include <aws/iot/MqttClient.h>

#include <aws/iotshadow/ErrorResponse.h>
#include <aws/iotshadow/IotShadowClient.h>
#include <aws/iotshadow/ShadowDeltaUpdatedEvent.h>
#include <aws/iotshadow/ShadowDeltaUpdatedSubscriptionRequest.h>
#include <aws/iotshadow/UpdateShadowRequest.h>
#include <aws/iotshadow/UpdateNamedShadowRequest.h>
#include <aws/iotshadow/UpdateShadowResponse.h>
#include <aws/iotshadow/UpdateShadowSubscriptionRequest.h>

#include <aws/iotshadow/GetShadowRequest.h>
#include <aws/iotshadow/GetShadowResponse.h>
#include <aws/iotshadow/GetShadowSubscriptionRequest.h>
#include <aws/iotshadow/UpdateShadowSubscriptionRequest.h>

#include <algorithm>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>

#include "../../../samples/utils/CommandLineUtils.h"

using namespace Aws::Crt;
using namespace Aws::Iotshadow;

void changeShadowValue(Aws::Crt::String thingName, String property, String value);
void changeNamedShadowValue(String thingName, String property, String value, String shadowName);

IotShadowClient *shadowClient = nullptr;
int main(int argc, char *argv[])
{
/************************ Setup ****************************/
ApiHandle apiHandle;

/**
* cmdData is the arguments/input from the command line placed into a single struct for
* use in this sample. This handles all of the command line parsing, validating, etc.
* See the Utils/CommandLineUtils for more information.
*/
Utils::cmdData cmdData = Utils::parseSampleInputJobs(argc, argv, &apiHandle);

/**
* In a real world application you probably don't want to enforce synchronous behavior
* but this is a sample console application, so we'll just do that with a condition variable.
*/
std::promise<bool> connectionCompletedPromise;
std::promise<void> connectionClosedPromise;
std::shared_ptr<Aws::Crt::Mqtt::MqttConnection> connection;

Aws::Iot::Mqtt5ClientBuilder *builder = Aws::Iot::Mqtt5ClientBuilder::NewMqtt5ClientBuilderWithMtlsFromPath(
cmdData.input_endpoint, cmdData.input_cert.c_str(), cmdData.input_key.c_str());

// Check if the builder setup correctly.
if (builder == nullptr)
{
printf(
"Failed to setup mqtt5 client builder with error code %d: %s", LastError(), ErrorDebugString(LastError()));
return -1;
}
// Create Mqtt5Client
std::shared_ptr<Aws::Crt::Mqtt5::Mqtt5Client> client5;
if (cmdData.input_mqtt_version == 5UL)
{
// Create the MQTT5 builder and populate it with data from cmdData.
// Setup connection options
std::shared_ptr<Mqtt5::ConnectPacket> connectOptions = std::make_shared<Mqtt5::ConnectPacket>();
connectOptions->WithClientId(cmdData.input_clientId);
builder->WithConnectOptions(connectOptions);
if (cmdData.input_port != 0)
{
builder->WithPort(static_cast<uint16_t>(cmdData.input_port));
}
// Setup lifecycle callbacks
builder->WithClientConnectionSuccessCallback(
[&connectionCompletedPromise](const Mqtt5::OnConnectionSuccessEventData &eventData) {
fprintf(
stdout,
"Mqtt5 Client connection succeed, clientid: %s.\n",
eventData.negotiatedSettings->getClientId().c_str());
connectionCompletedPromise.set_value(true);
});
builder->WithClientConnectionFailureCallback([&connectionCompletedPromise](
const Mqtt5::OnConnectionFailureEventData &eventData) {
fprintf(
stdout, "Mqtt5 Client connection failed with error: %s.\n", aws_error_debug_str(eventData.errorCode));
connectionCompletedPromise.set_value(false);
});
builder->WithClientStoppedCallback([&connectionClosedPromise](const Mqtt5::OnStoppedEventData &) {
fprintf(stdout, "Mqtt5 Client stopped.\n");
connectionClosedPromise.set_value();
});

client5 = builder->Build();
if (client5 == nullptr)
{
fprintf(
stdout,
"Failed to Init Mqtt5Client with error code %d: %s.\n",
LastError(),
ErrorDebugString(LastError()));
return -1;
}
fprintf(stdout, "Connecting...\n");
if (!client5->Start())
{
fprintf(stderr, "MQTT5 Connection failed to start");
exit(-1);
}
shadowClient = new IotShadowClient(client5);
}
else if (cmdData.input_mqtt_version == 3UL)
{
Aws::Iot::MqttClientConnectionConfigBuilder clientConfigBuilder;
// Create the MQTT builder and populate it with data from cmdData.
clientConfigBuilder =
Aws::Iot::MqttClientConnectionConfigBuilder(cmdData.input_cert.c_str(), cmdData.input_key.c_str());
clientConfigBuilder.WithEndpoint(cmdData.input_endpoint);
if (cmdData.input_ca != "")
{
clientConfigBuilder.WithCertificateAuthority(cmdData.input_ca.c_str());
}

// Create the MQTT connection from the MQTT builder
auto clientConfig = clientConfigBuilder.Build();
if (!clientConfig)
{
fprintf(
stderr,
"Client Configuration initialization failed with error %s\n",
Aws::Crt::ErrorDebugString(clientConfig.LastError()));
exit(-1);
}

Aws::Iot::MqttClient client3 = Aws::Iot::MqttClient();
connection = client3.NewConnection(clientConfig);
if (!*connection)
{
fprintf(
stderr,
"MQTT Connection Creation failed with error %s\n",
Aws::Crt::ErrorDebugString(connection->LastError()));
exit(-1);
}

// Invoked when a MQTT connect has completed or failed
auto onConnectionCompleted = [&](Mqtt::MqttConnection &, int errorCode, Mqtt::ReturnCode returnCode, bool) {
if (errorCode)
{
fprintf(stdout, "Connection failed with error %s\n", ErrorDebugString(errorCode));
connectionCompletedPromise.set_value(false);
}
else
{
fprintf(stdout, "Connection completed with return code %d\n", returnCode);
connectionCompletedPromise.set_value(true);
}
};

// Invoked when a disconnect has been completed
auto onDisconnect = [&](Mqtt::MqttConnection & /*conn*/) {
{
fprintf(stdout, "Disconnect completed\n");
connectionClosedPromise.set_value();
}
};

connection->OnConnectionCompleted = std::move(onConnectionCompleted);
connection->OnDisconnect = std::move(onDisconnect);

fprintf(stdout, "Connecting...\n");
if (!connection->Connect(cmdData.input_clientId.c_str(), true, 0))
{
fprintf(stderr, "MQTT Connection failed with error %s\n", ErrorDebugString(connection->LastError()));
exit(-1);
}
shadowClient = new IotShadowClient(connection);
}
else
{
fprintf(stderr, "MQTT Version not supported\n");
exit(-1);
}

delete builder;

/************************ Run the sample ****************************/
if (connectionCompletedPromise.get_future().get())
{
if (cmdData.input_shadowName.empty())
{
changeShadowValue(
cmdData.input_thingName,
cmdData.input_shadowProperty,
cmdData.input_shadowValue);
}
else
{
changeNamedShadowValue(
cmdData.input_thingName,
cmdData.input_shadowProperty,
cmdData.input_shadowValue,
cmdData.input_shadowName);
}

}
/************************ sample ends ****************************/
/* Closing down */
// Wait just a little bit to let the console print
std::this_thread::sleep_for(std::chrono::milliseconds(500));

if (cmdData.input_mqtt_version == 5UL)
{
// Disconnect
if (client5->Stop() == true)
{
connectionClosedPromise.get_future().wait();
}
}
else
{ // mqtt3

// Disconnect
if (connection->Disconnect() == true)
{
connectionClosedPromise.get_future().wait();
}
}
return 0;
}

void changeShadowValue(Aws::Crt::String thingName, String property, String value)
{
JsonObject desired;
JsonObject reported;
desired.WithObject(property, value);
reported.WithObject(property, value);

UpdateShadowRequest request;
request.ThingName = thingName;
request.State->Reported = reported;
request.State->Desired = desired;

auto publishCompleted = [thingName, value](int ioErr) {
if (ioErr != AWS_OP_SUCCESS)
{
fprintf(stderr, "Failed to update %s shadow state: error %s\n", thingName.c_str(), ErrorDebugString(ioErr));
return;
}

fprintf(stdout, "Successfully updated shadow state for %s, to %s\n", thingName.c_str(), value.c_str());
};
shadowClient->PublishUpdateShadow(request, AWS_MQTT_QOS_AT_LEAST_ONCE, publishCompleted);
}

void changeNamedShadowValue(String thingName, String property, String value, String shadowName)
{
JsonObject desired;
JsonObject reported;
desired.WithObject(property, value);
reported.WithObject(property, value);

UpdateNamedShadowRequest request;
request.ThingName = thingName;
request.State->Reported = reported;
request.State->Desired = desired;
request.ShadowName = shadowName;

auto publishCompleted = [thingName, value](int ioErr) {
if (ioErr != AWS_OP_SUCCESS)
{
fprintf(stderr, "Failed to update %s shadow state: error %s\n", thingName.c_str(), ErrorDebugString(ioErr));
return;
}

fprintf(stdout, "Successfully updated shadow state for %s, to %s\n", thingName.c_str(), value.c_str());
};
shadowClient->PublishUpdateNamedShadow(request, AWS_MQTT_QOS_AT_LEAST_ONCE, publishCompleted);
}

0 comments on commit e7e3e41

Please sign in to comment.