I cannot get the official aws-pubsub sdk to run. I have replaced all the necessary credentials. How can I set publishing and subscribing using my Android device on Amazon IoT? I have seen every link available on the web but still cannot get it to work. Here is an idea of my project:
The company is creating air filters that transmit data on regular basis through BLE module to the android app. Now I have to use this app to publish data to Amazon IoT as soon as it gets data from the BLE.
package com.example.parasrawat2124.amazonmqtt;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import com.amazonaws.auth.CognitoCachingCredentialsProvider;
import com.amazonaws.mobileconnectors.iot.AWSIotKeystoreHelper;
import com.amazonaws.mobileconnectors.iot.AWSIotMqttClientStatusCallback;
import com.amazonaws.mobileconnectors.iot.AWSIotMqttLastWillAndTestament;
import com.amazonaws.mobileconnectors.iot.AWSIotMqttManager;
import com.amazonaws.mobileconnectors.iot.AWSIotMqttNewMessageCallback;
import com.amazonaws.mobileconnectors.iot.AWSIotMqttQos;
import com.amazonaws.regions.Region;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.iot.AWSIotClient;
import com.amazonaws.services.iot.model.AttachPrincipalPolicyRequest;
import com.amazonaws.services.iot.model.CreateKeysAndCertificateRequest;
import com.amazonaws.services.iot.model.CreateKeysAndCertificateResult;
import java.io.UnsupportedEncodingException;
import java.security.KeyStore;
import java.util.UUID;
public class MainActivity extends AppCompatActivity {
static final String LOG_TAG = MainActivity.class.getCanonicalName();
// --- Constants to modify per your configuration ---
// IoT endpoint
// AWS Iot CLI describe-endpoint call returns: XXXXXXXXXX.iot.<region>.amazonaws.com
private static final String CUSTOMER_SPECIFIC_ENDPOINT = "a1j3ds5m9dpp07.iot.us-west-2.amazonaws.com";
// Cognito pool ID. For this app, pool needs to be unauthenticated pool with
// AWS IoT permissions.
private static final String COGNITO_POOL_ID = "us-west-2_iQ1FI8tfj";
// Name of the AWS IoT policy to attach to a newly created certificate
private static final String AWS_IOT_POLICY_NAME = "PMQTT";
// Region of AWS IoT
private static final Regions MY_REGION = Regions.US_EAST_1;
// Filename of KeyStore file on the filesystem
private static final String KEYSTORE_NAME = "iot_keystore";
// Password for the private key in the KeyStore
private static final String KEYSTORE_PASSWORD = "password";
// Certificate and key aliases in the KeyStore
private static final String CERTIFICATE_ID = "default";
EditText txtSubcribe;
EditText txtTopic;
EditText txtMessage;
TextView tvLastMessage;
TextView tvClientId;
TextView tvStatus;
Button btnConnect;
Button btnSubscribe;
Button btnPublish;
Button btnDisconnect;
AWSIotClient mIotAndroidClient;
AWSIotMqttManager mqttManager;
String clientId;
String keystorePath;
String keystoreName;
String keystorePassword;
KeyStore clientKeyStore = null;
String certificateId;
CognitoCachingCredentialsProvider credentialsProvider;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txtSubcribe = (EditText) findViewById(R.id.txtSubsribe);
txtTopic = (EditText) findViewById(R.id.txtTopic);
txtMessage = (EditText) findViewById(R.id.txtMessage);
tvLastMessage = (TextView) findViewById(R.id.tvLastMessage);
tvClientId = (TextView) findViewById(R.id.tvClientId);
tvStatus = (TextView) findViewById(R.id.tvStatus);
btnConnect = (Button) findViewById(R.id.btnConnect);
btnConnect.setOnClickListener(connectClick);
btnConnect.setEnabled(false);
btnSubscribe = (Button) findViewById(R.id.btnSubscribe);
btnSubscribe.setOnClickListener(subscribeClick);
btnPublish = (Button) findViewById(R.id.btnPublish);
btnPublish.setOnClickListener(publishClick);
btnDisconnect = (Button) findViewById(R.id.btnDisconnect);
btnDisconnect.setOnClickListener(disconnectClick);
// MQTT client IDs are required to be unique per AWS IoT account.
// This UUID is "practically unique" but does not _guarantee_
// uniqueness.
clientId = UUID.randomUUID().toString();
tvClientId.setText(clientId);
// Initialize the AWS Cognito credentials provider
credentialsProvider = new CognitoCachingCredentialsProvider(
getApplicationContext(), // context
COGNITO_POOL_ID, // Identity Pool ID
MY_REGION // Region
);
Region region = Region.getRegion(MY_REGION);
// MQTT Client
mqttManager = new AWSIotMqttManager(clientId, CUSTOMER_SPECIFIC_ENDPOINT);
// Set keepalive to 10 seconds. Will recognize disconnects more quickly but will also send
// MQTT pings every 10 seconds.
mqttManager.setKeepAlive(10);
// Set Last Will and Testament for MQTT. On an unclean disconnect (loss of connection)
// AWS IoT will publish this message to alert other clients.
AWSIotMqttLastWillAndTestament lwt = new AWSIotMqttLastWillAndTestament("my/lwt/topic",
"Android client lost connection", AWSIotMqttQos.QOS0);
mqttManager.setMqttLastWillAndTestament(lwt);
// IoT Client (for creation of certificate if needed)
mIotAndroidClient = new AWSIotClient(credentialsProvider);
mIotAndroidClient.setRegion(region);
keystorePath = getFilesDir().getPath();
keystoreName = KEYSTORE_NAME;
keystorePassword = KEYSTORE_PASSWORD;
certificateId = CERTIFICATE_ID;
// To load cert/key from keystore on filesystem
try {
if (AWSIotKeystoreHelper.isKeystorePresent(keystorePath, keystoreName)) {
if (AWSIotKeystoreHelper.keystoreContainsAlias(certificateId, keystorePath,
keystoreName, keystorePassword)) {
Log.i(LOG_TAG, "Certificate " + certificateId
+ " found in keystore - using for MQTT.");
// load keystore from file into memory to pass on connection
clientKeyStore = AWSIotKeystoreHelper.getIotKeystore(certificateId,
keystorePath, keystoreName, keystorePassword);
btnConnect.setEnabled(true);
} else {
Log.i(LOG_TAG, "Key/cert " + certificateId + " not found in keystore.");
}
} else {
Log.i(LOG_TAG, "Keystore " + keystorePath + "/" + keystoreName + " not found.");
}
} catch (Exception e) {
Log.e(LOG_TAG, "An error occurred retrieving cert/key from keystore.", e);
}
if (clientKeyStore == null) {
Log.i(LOG_TAG, "Cert/key was not found in keystore - creating new key and certificate.");
new Thread(new Runnable() {
@Override
public void run() {
try {
// Create a new private key and certificate. This call
// creates both on the server and returns them to the
// device.
CreateKeysAndCertificateRequest createKeysAndCertificateRequest =
new CreateKeysAndCertificateRequest();
createKeysAndCertificateRequest.setSetAsActive(true);
final CreateKeysAndCertificateResult createKeysAndCertificateResult;
createKeysAndCertificateResult =
mIotAndroidClient.createKeysAndCertificate(createKeysAndCertificateRequest);
Log.i(LOG_TAG,
"Cert ID: " +
createKeysAndCertificateResult.getCertificateId() +
" created.");
// store in keystore for use in MQTT client
// saved as alias "default" so a new certificate isn't
// generated each run of this application
AWSIotKeystoreHelper.saveCertificateAndPrivateKey(certificateId,
createKeysAndCertificateResult.getCertificatePem(),
createKeysAndCertificateResult.getKeyPair().getPrivateKey(),
keystorePath, keystoreName, keystorePassword);
// load keystore from file into memory to pass on
// connection
clientKeyStore = AWSIotKeystoreHelper.getIotKeystore(certificateId,
keystorePath, keystoreName, keystorePassword);
// Attach a policy to the newly created certificate.
// This flow assumes the policy was already created in
// AWS IoT and we are now just attaching it to the
// certificate.
AttachPrincipalPolicyRequest policyAttachRequest =
new AttachPrincipalPolicyRequest();
policyAttachRequest.setPolicyName(AWS_IOT_POLICY_NAME);
policyAttachRequest.setPrincipal(createKeysAndCertificateResult
.getCertificateArn());
mIotAndroidClient.attachPrincipalPolicy(policyAttachRequest);
runOnUiThread(new Runnable() {
@Override
public void run() {
btnConnect.setEnabled(true);
}
});
} catch (Exception e) {
Log.e(LOG_TAG,
"Exception occurred when generating new private key and certificate.",
e);
}
}
}).start();
}
}
View.OnClickListener connectClick = new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(LOG_TAG, "clientId = " + clientId);
try {
mqttManager.connect(clientKeyStore, new AWSIotMqttClientStatusCallback() {
@Override
public void onStatusChanged(final AWSIotMqttClientStatus status,
final Throwable throwable) {
Log.d(LOG_TAG, "Status = " + String.valueOf(status));
runOnUiThread(new Runnable() {
@Override
public void run() {
if (status == AWSIotMqttClientStatus.Connecting) {
tvStatus.setText("Connecting...");
} else if (status == AWSIotMqttClientStatus.Connected) {
tvStatus.setText("Connected");
} else if (status == AWSIotMqttClientStatus.Reconnecting) {
if (throwable != null) {
Log.e(LOG_TAG, "Connection error.", throwable);
}
tvStatus.setText("Reconnecting");
} else if (status == AWSIotMqttClientStatus.ConnectionLost) {
if (throwable != null) {
Log.e(LOG_TAG, "Connection error.", throwable);
}
tvStatus.setText("Disconnected");
} else {
tvStatus.setText("Disconnected");
}
}
});
}
});
} catch (final Exception e) {
Log.e(LOG_TAG, "Connection error.", e);
tvStatus.setText("Error! " + e.getMessage());
}
}
};
View.OnClickListener subscribeClick = new View.OnClickListener() {
@Override
public void onClick(View v) {
final String topic = txtSubcribe.getText().toString();
Log.d(LOG_TAG, "topic = " + topic);
try {
mqttManager.subscribeToTopic(topic, AWSIotMqttQos.QOS0,
new AWSIotMqttNewMessageCallback() {
@Override
public void onMessageArrived(final String topic, final byte[] data) {
runOnUiThread(new Runnable() {
@Override
public void run() {
try {
String message = new String(data, "UTF-8");
Log.d(LOG_TAG, "Message arrived:");
Log.d(LOG_TAG, " Topic: " + topic);
Log.d(LOG_TAG, " Message: " + message);
tvLastMessage.setText(message);
} catch (UnsupportedEncodingException e) {
Log.e(LOG_TAG, "Message encoding error.", e);
}
}
});
}
});
} catch (Exception e) {
Log.e(LOG_TAG, "Subscription error.", e);
}
}
};
View.OnClickListener publishClick = new View.OnClickListener() {
@Override
public void onClick(View v) {
final String topic = txtTopic.getText().toString();
final String msg = txtMessage.getText().toString();
try {
mqttManager.publishString(msg, topic, AWSIotMqttQos.QOS0);
} catch (Exception e) {
Log.e(LOG_TAG, "Publish error.", e);
}
}
};
View.OnClickListener disconnectClick = new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
mqttManager.disconnect();
} catch (Exception e) {
Log.e(LOG_TAG, "Disconnect error.", e);
}
}
};
}
And my console message:
07-23 12:06:20.595 18136-18168/com.example.parasrawat2124.amazonmqtt D/CognitoCachingCredentialsProvider: Clearing credentials from SharedPreferences
07-23 12:06:20.898 18136-18168/com.example.parasrawat2124.amazonmqtt E/com.example.parasrawat2124.amazonmqtt.MainActivity: Exception occurred when generating new private key and certificate.
com.amazonaws.AmazonServiceException: 1 validation error detected: Value 'us-west-2_iQ1FI8tfj' at 'identityPoolId' failed to satisfy constraint: Member must satisfy regular expression pattern: [\w-]+:[0-9a-f-]+ (Service: AmazonCognitoIdentity; Status Code: 400; Error Code: ValidationException; Request ID: b696c58e-8e42-11e8-b181-f1f1e5db8378)
at com.amazonaws.http.AmazonHttpClient.handleErrorResponse(AmazonHttpClient.java:730)
at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:405)
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:212)
at com.amazonaws.services.cognitoidentity.AmazonCognitoIdentityClient.invoke(AmazonCognitoIdentityClient.java:566)
at com.amazonaws.services.cognitoidentity.AmazonCognitoIdentityClient.getId(AmazonCognitoIdentityClient.java:448)
at com.amazonaws.auth.AWSAbstractCognitoIdentityProvider.getIdentityId(AWSAbstractCognitoIdentityProvider.java:172)
at com.amazonaws.auth.AWSEnhancedCognitoIdentityProvider.refresh(AWSEnhancedCognitoIdentityProvider.java:76)
at com.amazonaws.auth.CognitoCredentialsProvider.retryRefresh(CognitoCredentialsProvider.java:693)
at com.amazonaws.auth.CognitoCredentialsProvider.startSession(CognitoCredentialsProvider.java:665)
at com.amazonaws.auth.CognitoCredentialsProvider.getCredentials(CognitoCredentialsProvider.java:444)
at com.amazonaws.auth.CognitoCachingCredentialsProvider.getCredentials(CognitoCachingCredentialsProvider.java:485)
at com.amazonaws.auth.CognitoCachingCredentialsProvider.getCredentials(CognitoCachingCredentialsProvider.java:77)
at com.amazonaws.services.iot.AWSIotClient.invoke(AWSIotClient.java:7048)
at com.amazonaws.services.iot.AWSIotClient.createKeysAndCertificate(AWSIotClient.java:1119)
at com.example.parasrawat2124.amazonmqtt.MainActivity$1.run(MainActivity.java:177)
at java.lang.Thread.run(Thread.java:764)
I am sorry for asking a question based on such few credentials. I figured out the actual problem. The steps given in the official Github Readme file are correct but you need to consider some options below in case you encounter errors:
Don't use the default value of keystore credentials as written in the readme file. Create your own Keystore and then put those new credentials and alias in the app.
After the last step which is creating a policy in IoT , I would recommend creating a thing and a certificate and attach this policy to that certificate. This was the problem that occurred in my case.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.