利用GitHub上的温度传感器的例子做为讲解,实现从云端获取设备终端状态及使用Java模拟设备数据。其实和官网给的视频同样,只须要将终端设备的数据转换为支持MQTT协议传输的数据,云端就能够拿到数据了。java
1.云端:建立文件,及开启cloudCorenode
vim device.yaml //案例中的设备配置,直接使用请删除全部注释 #apiVersion,该属性定义了咱们从k8s获取改设备数据的url路径 apiVersion: devices.kubeedge.io/v1alpha1 kind: Device metadata: name: temperature3 labels: description: 'temperature3' manufacturer: 'test' spec: deviceModelRef: name: temperature3-model #与设备模板名称进行绑定 nodeSelector: nodeSelectorTerms: - matchExpressions: - key: '' operator: In values: - sunsheen-edge #部署该设备的节点 # status中的属性为咱们能够定义的属性,属性名为propertyName的属性与初始指望值 status: twins: - propertyName: temperatureState desired: metadata: type: string value: 'on' - propertyName: temperature desired: metadata: type: string value: ''
vim devicemodel.yaml //设备模板文件,直接使用请删除全部注释。 #apiVersion与设备端保持一致 apiVersion: devices.kubeedge.io/v1alpha1 kind: DeviceModel metadata: name: temperature3-model namespace: default spec: #属性与设备的保持一致,这里能够设备权限,这里咱们只能修改温度状态,没法控制实际温度 properties: - name: temperatureState description: Temperature collected from the edge device type: string: accessMode: ReadWrite defaultValue: 'on' - name: temperature description: Temperature collected from the edge device type: string: accessMode: ReadOnly defaultValue: ''
vim deployment.yaml //使用deployment控制器(k8s内容), 建立POD,边缘节点会自动去拉取镜像(很慢,建议手动拉取,或配置私有镜像仓库) apiVersion: apps/v1 kind: Deployment metadata: name: temperature3-mapper labels: app: temperature spec: replicas: 1 selector: matchLabels: app: temperature3 template: metadata: labels: app: temperature3 spec: hostNetwork: true nodeSelector: name: "sunsheen-edge" containers: - name: temperature3 image: kubeedge-mapper:v2.2 #须要部署的镜像 imagePullPolicy: IfNotPresent securityContext: privileged: true
2.边缘端:开启 mosquitto,启动edgeCoredocker
mosquitto -d -p 1883 //边缘端开启mosquitto,用于传输消息
<dependency> <groupId>org.yaml</groupId> <artifactId>snakeyaml</artifactId> <version>1.13</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.58</version> </dependency> <!-- http请求 --> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.2</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient-cache</artifactId> <version>4.5.2</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpmime</artifactId> <version>4.5.2</version> </dependency> <dependency> <groupId>org.eclipse.paho</groupId> <artifactId>org.eclipse.paho.client.mqttv3</artifactId> <version>1.2.0</version> </dependency>
import java.util.concurrent.ScheduledExecutorService; import org.eclipse.paho.client.mqttv3.*; import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; /** * @author wanchen.chen * @ClassName KubeedageClient * @Despriction: MQTTP 链接类,用于推送/订阅 消息 * @date 2020/4/15 9:20 * @Version 1.0 **/ public class KubeedageClient { private MqttMessage message; private MqttClient client; private MqttConnectOptions options; private MqttTopic clientTopic; private MqttTopic serverTopic; //定义主题,document为云端反馈的主题;update为边缘向云端推送的主题。temperature3为设备名称,其余都固定。 private static String clientTopicStr ="$hw/events/device/temperature3/twin/update/document"; private static String serverTopicStr ="$hw/events/device/temperature3/twin/update"; private static final String url ="tcp://0.0.0.0:1883"; //我这里是要打包为镜像部署,全部须要配置边缘节点的用户及密码 private static final String userName ="xxx"; private static final String password ="xxx"; private ScheduledExecutorService scheduler; public KubeedageClient(){ } /** * 初始化 */ public void start() { try { // host为主机名,clientid即链接MQTT的客户端ID,通常以惟一标识符表示,MemoryPersistence设置clientid的保存形式,默认为之内存保存 client = new MqttClient(url, "KubeEdgeClient", new MemoryPersistence()); // MQTT的链接设置 options = new MqttConnectOptions(); // 设置是否清空session,这里若是设置为false表示服务器会保留客户端的链接记录,这里设置为true表示每次链接到服务器都以新的身份链接 options.setCleanSession(true); // 设置链接的用户名 options.setUserName(userName); // 设置链接的密码 options.setPassword(password.toCharArray()); // 设置超时时间 单位为秒 options.setConnectionTimeout(10); // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并无重连的机制 options.setKeepAliveInterval(20); // 设置回调 client.setCallback(new PushCallback()); clientTopic = client.getTopic(clientTopicStr); serverTopic = client.getTopic(serverTopicStr); //setWill方法,若是项目中须要知道客户端是否掉线能够调用该方法。设置最终端口的通知消息 // options.setWill(clientTopoc, "close".getBytes(), 2, true); client.connect(options); } catch (Exception e) { e.printStackTrace(); } } /** * 订阅主题消息 */ public void listerData(){ //订阅消息 int[] Qos = {1}; String[] topic1 = {clientTopicStr}; try { client.subscribe(topic1, Qos); } catch (MqttException e) { e.printStackTrace(); } } /** * push 消息到主题 * @param topic * @param message * @throws MqttPersistenceException * @throws MqttException */ public void publish(MqttTopic topic , MqttMessage message) throws MqttPersistenceException, MqttException { MqttDeliveryToken token = topic.publish(message); token.waitForCompletion(); // System.out.println("message is published completely! " // + token.isComplete()); } /** * 发送消息 * @param deviceInfo */ public void putData(String deviceInfo){ message = new MqttMessage(); message.setQos(2); message.setRetained(true); message.setPayload(deviceInfo.getBytes()); try { publish(serverTopic,message); } catch (MqttException e) { e.printStackTrace(); } } }
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; import org.eclipse.paho.client.mqttv3.MqttCallback; import org.eclipse.paho.client.mqttv3.MqttMessage; /** * @author wanchen.chen * @ClassName PushCallback 发布消息的回调类 * @Despriction: 必须实现MqttCallback的接口并实现对应的相关接口方法CallBack 类将实现 MqttCallBack。 * 每一个客户机标识都须要一个回调实例。在此示例中,构造函数传递客户机标识以另存为实例数据。 * 在回调中,将它用来标识已经启动了该回调的哪一个实例。 * 必须在回调类中实现三个方法: * @date 2020/4/15 9:17 * @Version 1.0 **/ public class PushCallback implements MqttCallback { public void connectionLost(Throwable cause) { // 链接丢失后,通常在这里面进行重连 System.out.println("链接断开,能够作重连"); } public void deliveryComplete(IMqttDeliveryToken token) { System.out.println("deliveryComplete---------" + token.isComplete()); } public void messageArrived(String topic, MqttMessage message) throws Exception { // subscribe后获得的消息会执行到这里面,消息只能被消费一次 System.out.println("接收消息主题 : " + topic); System.out.println("接收消息Qos : " + message.getQos()); System.out.println("接收的消息为:"+str); } }
.yaml文件,用于json数据结构apache
event_id: 0 timestamp: 0 twin: temperature: actual: value: 0 metadata: type: Updated temperatureState: actual: value: height metadata: type: Updated
经过Java代码将其转换为JSON,将数据put进JSON中就能够发送了:json
import org.yaml.snakeyaml.Yaml; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import java.net.URL; import java.util.Map; /** * @author wanchen.chen * @ClassName AnalysisYAML * @Despriction: 解析YAML文件的内容 * @date 2020/4/28 9:32 * @Version 1.0 **/ public class AnalysisYAML { /** * 传参解析 * @param urlStr * @return */ public Map<String,Object> getYamlData(String urlStr){ URL url = AnalysisYAML.class.getClassLoader().getResource(urlStr); return analysisData(url); } /** * 默认解析 * @return */ public Map<String,Object> getYamlData(){ URL url = AnalysisYAML.class.getClassLoader().getResource("attribute.yaml"); return analysisData(url); } /** * 获取URL 解析内容 * @param url * @return */ public Map<String,Object> analysisData(URL url){ InputStream input = null; try { input = new FileInputStream(url.getFile()); } catch (FileNotFoundException e) { e.printStackTrace(); } Yaml yaml = new Yaml(); Map<String,Object> map = (Map<String,Object>)yaml.load(input); return map; } }
经过DockerFile将jar文件打包为镜像:vim
FROM java:latest RUN mkdir -p /usr RUN mkdir -p /usr/local COPY . /usr/local/ WORKDIR /usr/local EXPOSE 8892 ENTRYPOINT ["java","-jar","xxx.jar"] //在DockerFile 文件目录下建立镜像 docker build -t kubeedge-mapper:v2.0 .