package cn.iocoder.yudao.module.iot.gateway.protocol.coap; import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.module.iot.core.enums.IotProtocolTypeEnum; import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils; import cn.iocoder.yudao.module.iot.gateway.config.IotGatewayProperties.ProtocolProperties; import cn.iocoder.yudao.module.iot.gateway.protocol.IotProtocol; import cn.iocoder.yudao.module.iot.gateway.protocol.coap.handler.downstream.IotCoapDownstreamSubscriber; import cn.iocoder.yudao.module.iot.gateway.protocol.coap.handler.upstream.IotCoapAuthHandler; import cn.iocoder.yudao.module.iot.gateway.protocol.coap.handler.upstream.IotCoapAuthResource; import cn.iocoder.yudao.module.iot.gateway.protocol.coap.handler.upstream.IotCoapRegisterHandler; import cn.iocoder.yudao.module.iot.gateway.protocol.coap.handler.upstream.IotCoapRegisterResource; import cn.iocoder.yudao.module.iot.gateway.protocol.coap.handler.upstream.IotCoapRegisterSubHandler; import cn.iocoder.yudao.module.iot.gateway.protocol.coap.handler.upstream.IotCoapRegisterSubResource; import cn.iocoder.yudao.module.iot.gateway.protocol.coap.handler.upstream.IotCoapUpstreamHandler; import cn.iocoder.yudao.module.iot.gateway.protocol.coap.handler.upstream.IotCoapUpstreamTopicResource; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.eclipse.californium.core.CoapResource; import org.eclipse.californium.core.CoapServer; import org.eclipse.californium.core.config.CoapConfig; import org.eclipse.californium.elements.config.Configuration; import cn.hutool.core.lang.Assert; import java.util.concurrent.TimeUnit; /** * IoT CoAP 协议实现 *
* 基于 Eclipse Californium 实现,支持: * 1. 认证:POST /auth * 2. 设备动态注册:POST /auth/register/device * 3. 子设备动态注册:POST /auth/register/sub-device/{productKey}/{deviceName} * 4. 属性上报:POST /topic/sys/{productKey}/{deviceName}/thing/property/post * 5. 事件上报:POST /topic/sys/{productKey}/{deviceName}/thing/event/post * * @author 芋道源码 */ @Slf4j public class IotCoapProtocol implements IotProtocol { /** * 协议配置 */ private final ProtocolProperties properties; /** * 服务器 ID(用于消息追踪,全局唯一) */ @Getter private final String serverId; /** * 运行状态 */ @Getter private volatile boolean running = false; /** * CoAP 服务器 */ private CoapServer coapServer; /** * 下行消息订阅者 */ private IotCoapDownstreamSubscriber downstreamSubscriber; public IotCoapProtocol(ProtocolProperties properties) { IotCoapConfig coapConfig = properties.getCoap(); Assert.notNull(coapConfig, "CoAP 协议配置(coap)不能为空"); this.properties = properties; this.serverId = IotDeviceMessageUtils.generateServerId(properties.getPort()); } @Override public String getId() { return properties.getId(); } @Override public IotProtocolTypeEnum getType() { return IotProtocolTypeEnum.COAP; } @Override public void start() { if (running) { log.warn("[start][IoT CoAP 协议 {} 已经在运行中]", getId()); return; } try { // 1.1 创建 CoAP 配置 IotCoapConfig coapConfig = properties.getCoap(); Configuration config = Configuration.createStandardWithoutFile(); config.set(CoapConfig.COAP_PORT, properties.getPort()); config.set(CoapConfig.MAX_MESSAGE_SIZE, coapConfig.getMaxMessageSize()); config.set(CoapConfig.ACK_TIMEOUT, coapConfig.getAckTimeoutMs(), TimeUnit.MILLISECONDS); config.set(CoapConfig.MAX_RETRANSMIT, coapConfig.getMaxRetransmit()); // 1.2 创建 CoAP 服务器 coapServer = new CoapServer(config); // 2.1 添加 /auth 认证资源 IotCoapAuthHandler authHandler = new IotCoapAuthHandler(serverId); IotCoapAuthResource authResource = new IotCoapAuthResource(authHandler); coapServer.add(authResource); // 2.2 添加 /auth/register/device 设备动态注册资源(一型一密) IotCoapRegisterHandler registerHandler = new IotCoapRegisterHandler(); IotCoapRegisterResource registerResource = new IotCoapRegisterResource(registerHandler); // 2.3 添加 /auth/register/sub-device/{productKey}/{deviceName} 子设备动态注册资源 IotCoapRegisterSubHandler registerSubHandler = new IotCoapRegisterSubHandler(); IotCoapRegisterSubResource registerSubResource = new IotCoapRegisterSubResource(registerSubHandler); authResource.add(new CoapResource("register") {{ add(registerResource); add(registerSubResource); }}); // 2.4 添加 /topic 根资源(用于上行消息) IotCoapUpstreamHandler upstreamHandler = new IotCoapUpstreamHandler(serverId); IotCoapUpstreamTopicResource topicResource = new IotCoapUpstreamTopicResource(serverId, upstreamHandler); coapServer.add(topicResource); // 3. 启动服务器 coapServer.start(); running = true; log.info("[start][IoT CoAP 协议 {} 启动成功,端口:{},serverId:{}]", getId(), properties.getPort(), serverId); // 4. 启动下行消息订阅者 IotMessageBus messageBus = SpringUtil.getBean(IotMessageBus.class); this.downstreamSubscriber = new IotCoapDownstreamSubscriber(this, messageBus); this.downstreamSubscriber.start(); } catch (Exception e) { log.error("[start][IoT CoAP 协议 {} 启动失败]", getId(), e); stop0(); throw e; } } @Override public void stop() { if (!running) { return; } stop0(); } private void stop0() { // 1. 停止下行消息订阅者 if (downstreamSubscriber != null) { try { downstreamSubscriber.stop(); log.info("[stop][IoT CoAP 协议 {} 下行消息订阅者已停止]", getId()); } catch (Exception e) { log.error("[stop][IoT CoAP 协议 {} 下行消息订阅者停止失败]", getId(), e); } downstreamSubscriber = null; } // 2. 关闭 CoAP 服务器 if (coapServer != null) { try { coapServer.stop(); coapServer.destroy(); coapServer = null; log.info("[stop][IoT CoAP 协议 {} 服务器已停止]", getId()); } catch (Exception e) { log.error("[stop][IoT CoAP 协议 {} 服务器停止失败]", getId(), e); } } running = false; log.info("[stop][IoT CoAP 协议 {} 已停止]", getId()); } }