物联网系列--物联网终台框架搭建

(初次设计,如有错误之处,敬请指出,持续更新中)由于工作需要,需要搭建物联网终台,主要框架为:
在这里插入图片描述

1,协议包搭建: 总体使用netty框架。1,设计时确保只有一个程序入口。即:只用一个main函数,程序jar包运行不启动任何端口号,只能通过main函数,启动端口号,并执行协议解析操作。,协议解析时:要校验内容为:帧头:帧尾:数据长度,等信息,校验通过后,确认为一条合法帧,将设备解析后:通过http接口将数据上送到终台,执行相关业务,然后需要将程序的连接信息,存入到系统内存中。相关代码如下
程序入口:

/**
 * 程序入口类
 */
public class StartService {

	public static void main(String[] args) throws Exception {
		List<Integer> ports = Arrays.asList(9999);
		System.out.println("服务开始启动启动");
		StartPlcInstruct.start();
		ChineseProverbServer cps = new ChineseProverbServer();
		cps.run(ports);
	}

}

存入系统内存:

public class VoltmeterControllerPojo {

	

	public static Map<String, DatagramPacket> mapPacket = new HashMap<String, DatagramPacket>();// 存放回复消息变量值
	/**
	 *  存放发送消息时的变量,key为:设备地址a+设备地址b+packet,和 设备地址a+设备地址b+ctx
	 * */
	public static Map<String, ChannelHandlerContext> mapContext = new HashMap<String, ChannelHandlerContext>();

}

VoltmeterControllerPojo.mapPacket.put(hexValue.substring(6, 10)  + "packet", packet);
VoltmeterControllerPojo.mapContext.put(hexValue.substring(6, 10)  + "ctx", ctx);

协议包通过http接口将数据上送到物联网终台:

HttpUtils.sendPost("http://localhost:6606/qsPlc/sendMqtt", "state="+data+"&adress="+adress);

2,物联网终台,新建类与协议包中的接口对应: 物联网终台新建一个类,用来接受设备数据,读取产品管理中设计的物模型,从服务/事件/属性三个维度,封装json,将设备上传数据上传到mqtt中。
相关代码:

/**
	 * 发送mqtt消息
	 *
	 * @param state  设备数据
	 * @param adress 设备地址
	 * @return
	 */
	@PostMapping("/sendMqtt")
	public String sendMsg(String state, String adress) {

		
		JSONObject finalObject = new JSONObject();// 请求参数的最终json数据
		// 定义属性/服务/事件三个集合
		JSONArray jsarray = new JSONArray();
		finalObject.put("properties", jsarray);// 属性
		mqttGateway.sendToMqtt(finalObject.toString(), MqttPlcTopicType.TOPIC);
		return "success";
	}

3,设备命令下发: ,新建类,订阅业务层下发的指令,将信息,存入redis队列中。相关代码

public class ReceiveMessageHandler implements MessageHandler {

	@Override
	public void handleMessage(Message<?> message) throws MessagingException {
		// String topic =
		// message.getHeaders().get("mqtt_receivedTopic").toString();//订阅的主题
		String msg = message.getPayload().toString();
		System.out.println("接受到的消息 " + msg);

		Gson gson = new Gson();
		Map<String, Object> map = new HashMap<String, Object>();
		map = gson.fromJson(msg, map.getClass());
		String dataValue = map.get("dataValue").toString();
		map.put("dataValue", FormatString.getEquimentString(dataValue));
		
		 String str = JSON.toJSONString(map);
		
		// 处理设备控制,将下发的指令,存放到redis中
		 RedisUtil.setListValue(RedisToPic.TOPIC, str);
		
	}

}

设备控制命令下发: 在协议jar包处,启动定时任务,定时扫描redis队列,如果获取到redis存在待发送的指令,则取出消费,对设备下发控制指令。主要代码:

public class StartPlcInstruct {

	public static void start() {
		System.out.println("线程开始启动:定时查询需要下发的命令");
		/**
		 * Runnable:实现了Runnable接口,jdk就知道这个类是一个线程
		 */
		Runnable runnable = new Runnable() {
			// 创建 run 方法
			public void run() {
				Jedis consumer = RedisUtil.getJedis();

				String value = consumer.lpop("QS_PLC");
				if (value != null) {
					// 有数据则继续消费
					Gson gson = new Gson();
					Map<String, Object> map = new HashMap<String, Object>();
					map = gson.fromJson(value, map.getClass());
					try {
						PlcController.voltmeterController("03", map.get("dataValue").toString(),
								map.get("adress").toString());
					} catch (Exception e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		};

		// 做为并发工具类被引进的,这是最理想的定时任务实现方式。
		ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
		service.scheduleAtFixedRate(runnable, 10, 3, TimeUnit.SECONDS);
	}
}

至此:设备的注册、上报、控制,整体框架已经搭建完毕。整体目录结构如下:
在这里插入图片描述
这样搭建仍然有一些问题如下:诸位如果有解决方案,可私聊:
一:会存在命令失效的情况;
使用场景:1,设备在物联网终台已经注册过数据,此时关闭或者重启协议包:qs_iot_plc
原因:由于将设备的连接session存放在内存中,重启或者关闭协议包,导致内存重新加载将之间的连接信息清空。此时发送指令,由于获取不到连接信息,导致命令失效
二:存在命令未发送,或者命令发送失败,命令在redis中消失的情况
使用场景:在步骤一的基础上操作
原因:物联网终台:qs_iot,接受到业务层下发的指令,将信息存放到redis缓存中,协议包:qs_iot_plc,启动定时任务取消费指令队列,由于已经消费过指令队列中的数据,即使发送失败,数据也将不存在。

摸索中前行,欢迎广大同行,前来一起探讨

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值