我已经构建了一个ipad应用程序,我将其连接到一个传感器标签,该标签将温度数据发送到该应用程序。
我想做的是将温度数据发送到AWS IoT,想法是使用MQTT。我已经设置了一个本地服务器,将测试数据发送到AWS IoT,但我无法将设备连接到同一个端点。我认为这是因为本地服务器可以发布数据,因为它引用了证书和私钥。但在xcode中,我不知道如何做到这一点,所以如果没有证书和私钥参考,我认为iOS应用程序无法连接到物联网。这是正确的吗?
从这里出发,最好的方式是什么?我下载了AWS iOS SDK,但它似乎不支持物联网。
我在想,我可能可以让iOS应用程序将其数据发送到一个外部服务器,该服务器连接了证书和密钥,然后让服务器将数据发布到AWS IoT。
AWS iOS SDK已更新,支持AWS IoT。您现在可以与控件API交互,并建立与平台的连接,执行发布和订阅操作。
SDK主页:https://aws.amazon.com/documentation/sdk-for-ios/
发布/子界面:http://docs.aws.amazon.com/AWSiOSSDK/latest/Classes/AWSIoTDataManager.html
样品:https://github.com/awslabs/aws-sdk-ios-samples/tree/master/IoT-Sample/Swift/
除此之外,您还可以在AWS IoT中创建证书和策略,并将证书密钥插入iOS的TLS兼容MQTT客户端。GitHub上有一些。
不,没有证书就无法连接。最好的方法是编写一个函数来连接appdelegate中的aws-iot保存iot管理器和userdefault中的iot数据管理器对象。启动应用程序时,请检查对象,获取连接状态,如果未连接,请尝试再次连接。
首先初始化
func initalizeAWS(){
// Initialize AWSMobileClient for authorization
AWSMobileClient.sharedInstance().initialize { (userState, error) in
guard error == nil else {
print("Failed to initialize AWSMobileClient. Error: (error!.localizedDescription)")
return
}
print("AWSMobileClient initialized.")
}
// Init IOT
let iotEndPoint = AWSEndpoint(urlString: IOT_ENDPOINT)
// Configuration for AWSIoT control plane APIs
let iotConfiguration = AWSServiceConfiguration(region: AWSRegion, credentialsProvider: AWSMobileClient.sharedInstance())
// Configuration for AWSIoT data plane APIs
let iotDataConfiguration = AWSServiceConfiguration(region: AWSRegion,
endpoint: iotEndPoint,
credentialsProvider: AWSMobileClient.sharedInstance())
AWSServiceManager.default().defaultServiceConfiguration = iotConfiguration
iotManager = AWSIoTManager.default()
iot = AWSIoT.default()
AWSIoTDataManager.register(with: iotDataConfiguration!, forKey: ASWIoTDataManager)
iotDataManager = AWSIoTDataManager(forKey: ASWIoTDataManager)
}
连接到AWS IOT
func connectToAWS(){
func mqttEventCallback( _ status: AWSIoTMQTTStatus )
{
DispatchQueue.main.async {
print("connection status = (status.rawValue)")
switch(status)
{
case .connecting:
print( "Connecting..." )
case .connected:
self.connected = true
let defaults = UserDefaults.standard
let certificateId = defaults.string( forKey: "certificateId")
print(certificateId)
print( "Connected." )
//subscribe for topic when connected
self.subscribe(topic: topic)
case .disconnected:
print( "Disconnected" )
case .connectionRefused:
print( "Connection Refused" )
case .connectionError:
print( "Connection Error" )
case .protocolError:
print( "Protocol Error")
default:
print("unknown state: (status.rawValue)")
}
NotificationCenter.default.post( name: Notification.Name(rawValue: "connectionStatusChanged"), object: self )
}
}
if (connected == false)
{
let defaults = UserDefaults.standard
var certificateId = defaults.string( forKey: "certificateId")
if (certificateId == nil)
{
DispatchQueue.main.async {
print("No identity available, searching bundle...")
}
// No certificate ID has been stored in the user defaults; check to see if any .p12 files
// exist in the bundle.
let myBundle = Bundle.main
let myImages = myBundle.paths(forResourcesOfType: "p12" as String, inDirectory:nil)
let uuid = UUID().uuidString;
if (myImages.count > 0) {
// At least one PKCS12 file exists in the bundle. Attempt to load the first one
// into the keychain (the others are ignored), and set the certificate ID in the
// user defaults as the filename. If the PKCS12 file requires a passphrase,
// you'll need to provide that here; this code is written to expect that the
// PKCS12 file will not have a passphrase.
if let data = try? Data(contentsOf: URL(fileURLWithPath: myImages[0])) {
DispatchQueue.main.async {
print( "found identity (myImages[0]), importing...")
}
if AWSIoTManager.importIdentity( fromPKCS12Data: data, passPhrase:"", certificateId:myImages[0]) {
// Set the certificate ID and ARN values to indicate that we have imported
// our identity from the PKCS12 file in the bundle.
defaults.set(myImages[0], forKey:"certificateId")
defaults.set("from-bundle", forKey:"certificateArn")
DispatchQueue.main.async {
print("Using certificate: (myImages[0]))")
self.iotDataManager.connect( withClientId: uuid, cleanSession:true, certificateId:myImages[0], statusCallback: mqttEventCallback)
}
}
}
}
certificateId = defaults.string( forKey: "certificateId")
if (certificateId == nil) {
DispatchQueue.main.async {
print( "No identity found in bundle, creating one...")
}
// Now create and store the certificate ID in NSUserDefaults
let csrDictionary = [ "commonName":CertificateSigningRequestCommonName, "countryName":CertificateSigningRequestCountryName, "organizationName":CertificateSigningRequestOrganizationName, "organizationalUnitName":CertificateSigningRequestOrganizationalUnitName ]
self.iotManager.createKeysAndCertificate(fromCsr: csrDictionary, callback: { (response ) -> Void in
if (response != nil)
{
defaults.set(response?.certificateId, forKey:"certificateId")
defaults.set(response?.certificateArn, forKey:"certificateArn")
certificateId = response?.certificateId
print("response: [(String(describing: response))]")
let attachPrincipalPolicyRequest = AWSIoTAttachPrincipalPolicyRequest()
attachPrincipalPolicyRequest?.policyName = PolicyName
attachPrincipalPolicyRequest?.principal = response?.certificateArn
// Attach the policy to the certificate
self.iot.attachPrincipalPolicy(attachPrincipalPolicyRequest!).continueWith (block: { (task) -> AnyObject? in
if let error = task.error {
print("failed: [(error)]")
}
print("result: [(String(describing: task.result))]")
// Connect to the AWS IoT platform
if (task.error == nil)
{
DispatchQueue.main.asyncAfter(deadline: .now()+2, execute: {
print("Using certificate: (certificateId!)")
self.iotDataManager.connect( withClientId: uuid, cleanSession:true, certificateId:certificateId!, statusCallback: mqttEventCallback)
})
}
return nil
})
}
else
{
DispatchQueue.main.async {
print("Unable to create keys and/or certificate, check values in Constants.swift")
}
}
} )
}
}
else
{
let uuid = UUID().uuidString;
// Connect to the AWS IoT service
iotDataManager.connect( withClientId: uuid, cleanSession:true, certificateId:certificateId!, statusCallback: mqttEventCallback)
}
}
}
AWS 的缺陷
func disconnectToAWS(){
print("Disconnecting...")
DispatchQueue.global(qos: DispatchQoS.QoSClass.default).async {
self.iotDataManager.disconnect();
DispatchQueue.main.async {
self.connected = false
print( "Connect")
}
}
}
订阅主题
func subscribe(topic:String){
let iotDataManager = AWSIoTDataManager(forKey: ASWIoTDataManager)
iotDataManager.subscribe(toTopic: topic, qoS: .messageDeliveryAttemptedAtLeastOnce, messageCallback: {
(payload) ->Void in
let stringValue = NSString(data: payload, encoding: String.Encoding.utf8.rawValue)!
print("received: (stringValue)")
if let jsonDict = try? JSONSerialization.jsonObject(with: payload, options: []) as? [String: Any]{
DispatchQueue.main.async {
if let type = jsonDict?["message_type"] as? String{
if type == "veh_live_info"{
}
else if type == "oil_change_info"{
}
else{
}
}
}
}
} )
}
取消订阅主题
func unsubscribe(topic:String){
let iotDataManager = AWSIoTDataManager(forKey: ASWIoTDataManager)
iotDataManager.unsubscribeTopic(topic)
}
参考:https://github.com/awslabs/aws-sdk-ios-samples/tree/master/IoT-Sample/Swift/
有一种方法可以做到这一点,而不需要用户使用AWS Cognito进行身份验证,也不需要为每个客户端生成X.509证书(就像上面的方法需要-github示例/放大)
我写了一篇关于如何简单地使用AWS iOS SDK做到这一点的文章,不需要身份验证。可能对您的用例有用:
- 在Medium上(认为它可能在付费墙后面)
- 物联网(应该是可访问的——否则这个名字会很讽刺,哈哈)