转载

探索 IBM Bluemix 上的 MQTT 和物联网服务

 

IBM Bluemix Internet of Things (IoT) 服务提供了简单且强大的功能将全球不同种类的设备和应用程序互联起来。这是如何实现的?Bluemix IoT 服务背后的秘密在于 MQTT,也就是消息队列遥测传输。在本教程中,您将了解 MQTT 的工作原理,以及如何使用 IoT 服务轻松地构建应用程序。

构建您的应用程序所需的准备工作

 

MQTT 是一个基于 TCP/IP 协议的简单、轻量型的发布/订阅消息协议,是新兴 IoT 领域的理想之选。

一般来讲,Bluemix IoT 服务充当着 MQTT 代理,因此负责将消息分发给已连接的客户端(设备和应用程序)。设备 包括各种机器,会发布它们所检测到的信息,应用程序 是各种程序,会使用从这些服务收到的信息。设备和应用程序使用 MQTT 协议与 MQTT 代理通信,如下图所示:

探索 IBM Bluemix 上的 MQTT 和物联网服务


使用 Bluemix IoT 服务的应用程序通常包含 3 部分:

  • Bluemix IoT 服务配置(设备和应用程序注册)
  • 设备端编程
  • 应用程序端编程

准备好尝试一下吗?

第 1 步. 设置 Bluemix IoT 服务

 

在这一步中,您将向 Bluemix IoT 服务注册各种设备和应用程序。

在仪表板上创建一个应用程序

 
  1. 使用您的 Bluemix 帐户登录 Bluemix
  2. 单击顶部菜单中的 Catalog
  3. 在 Boilerplates 部分中,单击 Internet of Things Foundation Starter
  4. 在 Name 字段中,为应用程序指定一个惟一的名称。对于本教程,我使用 bluemixmqtt
  5. 单击 CREATE。等待应用程序启动。

添加 IoT 服务

 
  1. 单击 ADD A SERVICE
  2. 选择 Internet of Things 部分下的 Internet of Things service
  3. 单击 CREATE。如果出现提示,单击 Restage

现在您已创建了一个拥有 IoT 服务的应用程序,如下图所示:

探索 IBM Bluemix 上的 MQTT 和物联网服务

启动 IoT 服务控制台

 
  1. 导航到应用程序的 Overview 页面,单击 Internet of Things
  2. 单击 Launch dashboard,打开 IoT 服务控制台。

注册设备

 
  1. 单击 Devices 选项卡下的 Add Device探索 IBM Bluemix 上的 MQTT 和物联网服务
  2. 为 Device Type 选项选择 Create a device type
  3. 在 Device Type 中填入 MQTTDevice。我们在后面将使用该值。
  4. 在 Device ID 中填入一个惟一的 id,比如 aabbccddee12。您可输入您自己的标识符。
  5. 单击 Continue探索 IBM Bluemix 上的 MQTT 和物联网服务
  6. 复制设备的信息;我们在后面会用到它。 探索 IBM Bluemix 上的 MQTT 和物联网服务
  7. 单击 Done

如果愿意,重复执行上述步骤,注册更多的设备。

注册应用程序

 
  1. 在 API Keys 选项卡下,单击 New API Key探索 IBM Bluemix 上的 MQTT 和物联网服务
  2. 复制 New API Key 对话框中的信息;我们在后面会用到它。 探索 IBM Bluemix 上的 MQTT 和物联网服务
  3. 单击 OK

如果愿意,重复执行上述步骤,注册更多的应用程序。

第 2 步. 创建一个设备端程序

 

设备端编程工作涉及 3 部分:

  • 连接到 IoT 服务(MQTT 代理)
  • 将事件发布到应用程序
  • 从应用程序订阅命令

在本节中,您将使用 Eclipse Paho Java 在 Java 中构建一个简单的设备端程序。有关更多信息,请参见 源代码

连接到 IoT 服务

 

IoT 服务(MQTT 代理)的访问点是 <orgid>.messaging.internetofthings.ibmcloud.com,其中 <orgid> 是在配置 IoT 服务时自动创建的。您可使用 TCP 或 TLS(传输层安全)。

点击查看代码清单

tcp://<org-id>.messaging.internetofthings.ibmcloud.com:1883
ssl://<org-id>.messaging.internetofthings.ibmcloud.com:8883

以设备客户端的身份连接到 IoT 服务之前,您必须设置 MQTT 连接选项。

  • client-id 属性的格式应为 d:<orgid>:<type-id>:<divice-id>


    <orgid> 与上面相同,而 <type-id><divice-id> 是之前注册设备时输入的。

  • authmethod 属性应设置为 use-token-auth
  • authtoken 属性应设置为之前所复制的设备信息中的 auth-token 字段内容。

下面的代码段来自类 com.ibm.bluemixmqtt.MqttHandler.java。您可选择使用 TCP 或 TLS。如果使用 TLS,应该将属性 com.ibm.ssl.protocol 设置为 TLSv1.2;否则连接可能失败。

	public void connect(String serverHost, String clientId, String authmethod,
			String authtoken, boolean isSSL) {
		// check if client is already connected
		if (!isMqttConnected()) {
			String connectionUri = null;
			
			//tcp://<org-id>.messaging.internetofthings.ibmcloud.com:1883
			//ssl://<org-id>.messaging.internetofthings.ibmcloud.com:8883
			if (isSSL) {
				connectionUri = "ssl://" + serverHost + ":" + DEFAULT_SSL_PORT;
			} else {
				connectionUri = "tcp://" + serverHost + ":" + DEFAULT_TCP_PORT;
			}
                       
			if (client != null) {
				try {
					client.disconnect();
				} catch (MqttException e) {
					e.printStackTrace();
				}
				client = null;
			}
                       
			try {
				client = new MqttClient(connectionUri, clientId);
			} catch (MqttException e) {
				e.printStackTrace();
			}
                       
			client.setCallback(this);
                       
			// create MqttConnectOptions and set the clean session flag
			MqttConnectOptions options = new MqttConnectOptions();
			options.setCleanSession(true);
                      
			options.setUserName(authmethod);
			options.setPassword(authtoken.toCharArray());
                      
			//If SSL is used, do not forget to use TLSv1.2
			if (isSSL) {
				java.util.Properties sslClientProps = new java.util.Properties();
				sslClientProps.setProperty("com.ibm.ssl.protocol", "TLSv1.2");
				options.setSSLProperties(sslClientProps);
			}
                      
			try {
				// connect
				client.connect(options);
				System.out.println("Connected to " + connectionUri);
			} catch (MqttException e) {
				e.printStackTrace();
			}
		}
	}

下面的代码段来自类 com.ibm.bluemixmqtt.DeviceTest.java。此代码读取配置文件,并使用配置文件中格式正确的值设置 MQTT 连接选项。

               //Read properties from the conf file
		Properties props = MqttUtil.readProperties("device.conf");
               
		String org = props.getProperty("org");
		String id = props.getProperty("deviceid");
		String authmethod = "use-token-auth";
		String authtoken = props.getProperty("token");
		//isSSL property
		String sslStr = props.getProperty("isSSL");
		boolean isSSL = false;
		if (sslStr.equals("T")) {
			isSSL = true;
		}
               
		System.out.println("org: " + org);
		System.out.println("id: " + id);
		System.out.println("authmethod: " + authmethod);
		System.out.println("authtoken: " + authtoken);
		System.out.println("isSSL: " + isSSL);
               
		String serverHost = org + MqttUtil.SERVER_SUFFIX;
               
		//Format: d:<orgid>:<type-id>:<divice-id>
		String clientId = "d:" + org + ":" + MqttUtil.DEFAULT_DEVICE_TYPE + ":"
				+ id;
		handler = new DeviceMqttHandler();
		handler.connect(serverHost, clientId, authmethod, authtoken, isSSL);

备注:要想连接 Bluemix IoT 服务,必须使用最低版本级别为 3.1 的 MQTT;推荐使用 MQTT 3.1.1,该版本中的功能更多。

发布事件

 

您应该使用这种形式发布各种事件主题:iot-2/evt/<event-id>/fmt/<format>。设置 <event-id> 可将不同的事件类型分类;您可选择自己的值。<format> 设置为 json。消息应编码成 JSON 格式,它必须包含单个名为 “d” 的顶级属性。

以下代码段来自类 com.ibm.bluemixmqtt.DeviceTest.java。它将消息编码为 JSON 格式并发布到正确的主题。

                      //Format the Json String
			JSONObject contObj = new JSONObject();
			JSONObject jsonObj = new JSONObject();
			try {
				contObj.put("count", count);
				contObj.put("time", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
						.format(new Date()));
				jsonObj.put("d", contObj);
			} catch (JSONException e1) {
				e1.printStackTrace();
			}
                       
			System.out.println("Send count as " + count);
                      
			//Publish device events to the app
			//iot-2/evt/<event-id>/fmt/<format>
			handler.publish("iot-2/evt/" + MqttUtil.DEFAULT_EVENT_ID
					+ "/fmt/json", jsonObj.toString(), false, 0);

在我们的示例设备程序中,我们发布事件时计数值从 0 开始,每隔 15 秒递增一次。下面是一条示例消息。注意,事件 JSON 消息中需要顶级属性 “d”。

{
    "d": {
        "count": 3,
        "time": "2014-12-30 16:14:59"
    }
}

订阅命令

 

订阅命令的主题应为以下格式:iot-2/cmd/<cmd-type>/fmt/<format-id>。设置 <cmd-type> 可将不同的命令类型分类;您可选择自己的值。可使用加号(“+”)作为通配符来设置 <cmd-type>,这样它可订阅各种命令类型。<format-id> 设置为 json

下面的代码段来自类 com.ibm.bluemixmqtt.DeviceTest.java。它演示了如何订阅命令消息。

               //Subscribe the Command events
		//iot-2/cmd/<cmd-type>/fmt/<format-id>
		handler.subscribe("iot-2/cmd/" + MqttUtil.DEFAULT_CMD_ID + "/fmt/json",
				0);

收到一个命令事件后,系统会执行回调函数 messageArrived。下面的代码段来自 com.ibm.bluemixmqtt.DeviceTest.java。在我们的示例应用程序中,从应用程序端收到该命令时,会将计数重置到从该命令所提取的值。

               public void messageArrived(String topic, MqttMessage mqttMessage)
				throws Exception {
			super.messageArrived(topic, mqttMessage);
			
			//Check whether the event is a command event from app
			if (topic.equals("iot-2/cmd/" + MqttUtil.DEFAULT_CMD_ID
					+ "/fmt/json")) {
				String payload = new String(mqttMessage.getPayload());
				JSONObject jsonObject = new JSONObject(payload);
				String cmd = jsonObject.getString("cmd");
				//Reset the count
				if (cmd != null && cmd.equals("reset")) {
					int resetcount = jsonObject.getInt("count");
					count = resetcount;
					System.out.println("Count is reset to " + resetcount);
				}
			}
		}

备注:有关设备端编程的更多信息,请参阅 https://developer.ibm.com/iot/recipes/improvise-connect-quickstart/

第 3 步. 创建应用程序端程序

 

与设备端编程一样,应用程序端编程包含 3 部分工作:

  • 连接到 IoT 服务(MQTT 代理)
  • 从设备或从 MQTT 代理订阅事件
  • 向设备发布命令

在本节中,您将使用 Eclipse Paho Java 在 Java 中构建一个简单的应用程序端程序。有关更多信息,请参见 源代码

连接到 IoT 服务

 

IoT 服务的访问点与设备端相同,但 MQTT 连接选项格式之间存在一些差异:

  • client-id 属性的格式应该是 a:<orgid>:<app-id>。<orgid> 与设备端相同,<app-id> 是为应用程序设置的惟一 id;您可选择自己的 id。
  • authmethod 和 authtoken 属性应设置为之前所复制的应用程序信息中的相关字段(Key 和 Auth Token)内容。

下面的代码段来自类 com.ibm.bluemixmqtt.APPTest.java。它读取配置文件,并使用配置文件中格式正确的值设置 MQTT 连接属性。

               //Read properties from the conf file
		Properties props = MqttUtil.readProperties("app.conf");
               
		String org = props.getProperty("org");
		String id = props.getProperty("appid");
		String authmethod = props.getProperty("key");
		String authtoken = props.getProperty("token");
		//isSSL property
		String sslStr = props.getProperty("isSSL");
		boolean isSSL = false;
		if (sslStr.equals("T")) {
			isSSL = true;
		}
		
		System.out.println("org: " + org);
		System.out.println("id: " + id);
		System.out.println("authmethod: " + authmethod);
		System.out.println("authtoken" + authtoken);
		System.out.println("isSSL: " + isSSL);
               
		//Format: a:<orgid>:<app-id>
		String clientId = "a:" + org + ":" + id;
		String serverHost = org + MqttUtil.SERVER_SUFFIX;
               
		handler = new AppMqttHandler();
		handler.connect(serverHost, clientId, authmethod, authtoken, isSSL);

订阅事件

 

应用程序端可订阅两种类型的事件:(1) 来自设备端的状态消息 (2) 系统生成的连接监视器消息。

  • 订阅设备端事件的主题应为以下格式:iot-2/type/<type-id>/id/<device-id>/evt/<event-id>/fmt/<format-id>。它应与设备端的事件格式保持一致。可使用加号(“+”)作为通配符,它将与主题树中的一个级别准确匹配。
  • 订阅系统事件的主题应为以下格式:iot-2/type/<type-id>/id/<device-id>/mon。在本例中,也可使用加号(“+”)作为通配符。通过订阅系统事件,每次设备与 IoT 服务连接或断开连接时,都可收到消息。

下面的代码段来自类 com.ibm.bluemixmqtt.APPTest.java。系统和设备事件都已订阅。

               handler.subscribe("iot-2/type/" + MqttUtil.DEFAULT_DEVICE_TYPE
				+ "/id/+/mon", 0);
		
		//Subscribe Device Events
		//iot-2/type/<type-id>/id/<device-id>/evt/<event-id>/fmt/<format-id>
		handler.subscribe("iot-2/type/" + MqttUtil.DEFAULT_DEVICE_TYPE
				+ "/id/+/evt/" + MqttUtil.DEFAULT_EVENT_ID + "/fmt/json", 0);

收到一个事件后,系统会执行回调函数 messageArrived。在我们的示例应用程序中,会检查消息中的计数值。如果计数值大于 4,则启动一个新线程来向相应的设备发布一个命令,从而将计数值重置为 0。有关更多信息,请参阅类 com.ibm.bluemixmqtt.APPTest.java 文件。

             public void messageArrived(String topic, MqttMessage mqttMessage)
				throws Exception {
			super.messageArrived(topic, mqttMessage);
                       
			Matcher matcher = pattern.matcher(topic);
			if (matcher.matches()) {
				String deviceid = matcher.group(1);
				String payload = new String(mqttMessage.getPayload());
				
				//Parse the payload in Json Format
				JSONObject jsonObject = new JSONObject(payload);
				JSONObject contObj = jsonObject.getJSONObject("d");
				int count = contObj.getInt("count");
				System.out.println("Receive count " + count + " from device "
						+ deviceid);
                         
				//If count >=4, start a new thread to reset the count
				if (count >= 4) {
					new ResetCountThread(deviceid, 0).start();
				}
			}
		}

发布命令

 

发布命令的主题应为以下格式:iot-2/cmd/<cmd-type>/fmt/<format-id>。它应与设备端上的命令格式保持一致。

下面的代码段来自类 com.ibm.bluemixmqtt.APPTest.java。一旦计数值达到 4,该类会将 reset 命令发布到相应的设备。当然,该命令也被编码为 JSON 格式。

                      JSONObject jsonObj = new JSONObject();
			try {
				jsonObj.put("cmd", "reset");
				jsonObj.put("count", count);
				jsonObj.put("time", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
						.format(new Date()));
			} catch (JSONException e) {
				e.printStackTrace();
			}
			System.out.println("Reset count for device " + deviceid);
			
			//Publish command to one specific device
			//iot-2/type/<type-id>/id/<device-id>/cmd/<cmd-id>/fmt/<format-id>
			handler.publish("iot-2/type/" + MqttUtil.DEFAULT_DEVICE_TYPE
					+ "/id/" + deviceid + "/cmd/" + MqttUtil.DEFAULT_CMD_ID
					+ "/fmt/json", jsonObj.toString(), false, 0);

备注:有关应用程序端编程的更多信息,请参阅 https://developer.ibm.com/iot/recipes/improvise-application-development/

第 4 步. 运行应用程序

 

构建项目

 
  1. 通过 源代码 创建代码分支。
  2. 在本地使用 Eclipse 构建项目并将其导出为 jar 归档文件,比如 “bluemixmqtt.jar”。如果不想自己进行编译,可在 MyData 文件夹下找到已编译的示例和其他已引用的库。

备注:项目需要 Java SDK 7.0 或更高版本。

更新应用程序端配置文件

 

应用程序端配置文件位于 MyData/app.conf 中。根据之前注册应用程序时所复制的属性来更新它。

#Configuration files for App Side Applications
           
#The org field is the same org field as the Device side
org=<org>
           
# A unique id you choose it by yourself, maybe, abcdefg123456
appid=<appid>
           
# The key field from App Keys info you copied previously
key=<Key>
           
# The Auth Token field from App Keys info you copied previously
token=<Auth_Token>
           
#T or F, T means using SSL, while F means not
isSSL=F

运行应用程序端程序

 

更新配置文件后,打开命令行,转到 MyData 文件夹,然后执行下面这条命令,运行应用程序端程序:
java -cp .;org.eclipse.paho.client.mqttv3.jar;json4j-apache-1.1.0.jar;bluemixmqtt.jar com.ibm.bluemixmqtt.AppTest

应用程序端程序成功连接到 IoT 服务后,您应收到与下面类似的确认消息:

探索 IBM Bluemix 上的 MQTT 和物联网服务

更新设备端配置文件

 

设备端配置文件位于 MyData/device.conf 中。根据之前注册设备时所复制的属性来更新它。

#Configuration files for Device Side Applications
           
#The org field from Device info you copied previously
org=<org>
           
#The id field from Device info you copied previously
deviceid=<id>
           
#The auth-token field from Device info you copied previously
token=<auth-token>
           
#T or F, T means using SSL, while F means not
isSSL=F

运行设备端程序

 

更新配置文件后,打开命令行,转到 MyData 文件夹,然后执行以下命令,运行设备端程序。
java -cp .;org.eclipse.paho.client.mqttv3.jar;json4j-apache-1.1.0.jar;bluemixmqtt.jar com.ibm.bluemixmqtt.DeviceTest

设备端程序成功连接到 IoT 服务后,应收到与下面类似的确认消息:

探索 IBM Bluemix 上的 MQTT 和物联网服务

检查正在运行的应用程序

 

设备端程序会发布状态事件消息(计数值从 0 开始,每隔 15 秒递增)。您可通过命令行找到相关的日志(包括事件和命令消息细节)。

此外,您可按照下面的步骤查看 IoT 服务控制台上的事件细节。

  1. 导航到 IoT 服务控制台。
  2. 在 Devices 选项卡上,观察相关设备的事件。在本例中,设备 id 为 aabbccddee12探索 IBM Bluemix 上的 MQTT 和物联网服务

    点击查看大图

  3. 单击一个事件,查看消息的详细信息。

    请注意 count 字段。如前所述,count 字段的值从 0 开始递增。其值达到 4 时,应用程序端程序向相应的设备发布一条命令,将该值重置为 0。所以计数值始终在 0 到 4 之间,绝不会超出该范围。

    探索 IBM Bluemix 上的 MQTT 和物联网服务

了解更多信息

 

通过执行上述操作,您使用 Bluemix IoT 服务并通过 MQTT 协议构建了应用程序。如果您熟悉 MQTT 客户端编程,可能会发现二者之间没有什么太大的差别,除了使用 Bluemix IoT 服务时,您必须确保一些属性(比如 MQTT 连接选项、发布和订阅主题表单等)要符合正确的格式要求。

如果解决方案基于现有的 MQTT 客户端库,那么使用 Bluemix IoT 服务构建解决方案会更容易。好消息是,目前有大量针对不同平台的 开源库,比如 C、C++、Java、JavaScript、Ruby、Go 等。

Bluemix IoT 服务支持各种连网的智能设备,比如 Arduino Uno、Raspberry Pi 等。请参阅 Bluemix 文档,了解详细信息。如果您的设备位于列表中,应该首先学习示例代码。前面讨论的 MQTT 机制应该可以帮助您理解和修改源代码。如果设备未在列表中,不要担心。就像我在示例应用程序中使用 Java 实现设备端程序一样,您可使用 MQTT 客户端库轻松地构建自己的程序。

我使用 Java 实现了我的应用程序端程序,但您也可以选择其他编程语言,比如 Node.js 或 Ruby。为了使应用程序端编程工作更容易,您可使用基于浏览器的流编辑器 Node-RED,而不是在本地进行编码。无论是自行构建还是通过 Node-RED 构建程序,Bluemix IoT 服务背后的 MQTT 流都具有相同的工作方式。

通过 Node-RED 执行应用程序端编程(可选)

 

如果有兴趣使用 Node-RED 工具构建应用程序端程序,可执行以下操作步骤。

Node-RED 基于 Node.js 运行时,包含在我们之前创建的 Internet of Things Foundation Starter 样板中。

  1. 导航到应用程序 URL,通常是 http://<app_name>.mybluemix.net。在本例中是 http://bluemixmqtt.mybluemix.net
  2. 单击 Go to your Node-RED flow editor 按钮。您可能需要稍微向下滚动页面才能看到该按钮。
  3. 单击右上角的菜单符号。将鼠标指针悬停在 Workspaces 上,单击 Add 添加一个新工作区。 探索 IBM Bluemix 上的 MQTT 和物联网服务
  4. 单击右上角的菜单符号。将鼠标指针悬停在 Import... 上,单击 Clipboard 导入流。探索 IBM Bluemix 上的 MQTT 和物联网服务
  5. 源代码 中 MyData/redsample.txt 的内容复制到 Nodes 文本字段,然后单击 OK探索 IBM Bluemix 上的 MQTT 和物联网服务
  6. 一条确认消息表明已导入了该流。探索 IBM Bluemix 上的 MQTT 和物联网服务
  7. 双击每个流块。您将看到它的配置对话框。这些参数可能看起来很熟悉,因为它们与在 Java 中构建应用程序端程序时使用的参数类似。 探索 IBM Bluemix 上的 MQTT 和物联网服务

    点击查看大图

  8. 单击右上角的 Deploy 按钮,部署应用程序端程序。
  9. 您可再次运行设备端程序,而且将获得类似的结果。在编辑器的右侧窗格中,也可查看来自设备端的消息。

使用 Node-RED GUI 编辑器构建应用程序端程序对用户而言要更容易一些。Node-RED 提供了许多内置的流块,您可轻松地将它们连接起来并直接进行部署。有关在 IoT 上使用 Node-RED 的更多信息,请参阅 Bluemix 文档

备注:不需要手动在 IoT 服务控制台中注册应用程序,因为使用 Node-RED 编辑器时,会自动注册该应用程序。请在出现提示时选择 Bluemix Service for Authentication 选项。

结束语

 

使用 Bluemix Internet of Things (IoT) 服务构建应用程序既简单又有趣。在本教程中,我们分析了 IoT 服务背后的 MQTT,解释了它的工作原理。一个循序渐进的教程展示了如何使用 MQTT,通过 Java 或 Node-RED 编辑器构建一个示例解决方案。因为您可在许多不同的场景中使用 IoT 概念,所以可将示例应用程序作为参考,使用 Bluemix IoT 服务合成自己的解决方案,帮助与全世界实现互联。

本教程所使用的 Bluemix 服务:Internet of Things 服务为应用程序提供了简单且强大的方法,使其可轻松访问 IoT 设备和数据。


相关主题:IoTMQTTEclipse Paho Java


    
正文到此结束
Loading...