SpringBoot與Californium整合,實(shí)現(xiàn)物聯(lián)網(wǎng)設(shè)備低功耗通信系統(tǒng)
CoAP是一種專門為物聯(lián)網(wǎng)設(shè)備設(shè)計(jì)的輕量級(jí)協(xié)議,特別適用于資源受限的環(huán)境。它通過簡(jiǎn)單的二進(jìn)制消息格式、高效的傳輸機(jī)制和RESTful架構(gòu),使得在低帶寬、高延遲和不可靠網(wǎng)絡(luò)條件下進(jìn)行通信變得容易。
哪些公司使用Californium?
- Intel Corporation在其 IoT 平臺(tái)和開發(fā)工具中集成 Californium 以支持 CoAP 協(xié)議。
- IBM利用 Californium 在其 IoT 和邊緣計(jì)算解決方案中實(shí)現(xiàn)高效的數(shù)據(jù)傳輸。
- 西門子使用 Californium 在其 IoT 解決方案中實(shí)現(xiàn)低功耗設(shè)備的通信。
- Bosch Rexroth利用 Californium 支持其工業(yè) IoT 應(yīng)用程序中的 CoAP 通信。
- Infineon Technologies 在其嵌入式系統(tǒng)和 IoT 解決方案中集成 Californium 以支持 CoAP 協(xié)議。
- 愛立信在其 IoT 平臺(tái)中使用 Californium 實(shí)現(xiàn)高效的設(shè)備間通信。
- Texas Instruments Inc.提供基于 Californium 的開發(fā)套件和示例代碼,助力開發(fā)者構(gòu)建 IoT 應(yīng)用。
- ABB Ltd.在其智能制造解決方案中利用 Californium 實(shí)現(xiàn)高效的數(shù)據(jù)交換和控制。
- Cisco Systems, Inc.在其 IoT 平臺(tái)上使用 Californium 實(shí)現(xiàn)低延遲和可靠的設(shè)備通信。
Californium的特點(diǎn)
- 輕量級(jí): 適合資源受限的設(shè)備。
- 可靠傳輸: 支持確認(rèn)消息(CON)、非確認(rèn)消息(NON)和重置消息(RST)。
- 多播支持: 允許向一組設(shè)備發(fā)送請(qǐng)求。
- 觀察機(jī)制: 客戶端可以訂閱資源變化,實(shí)時(shí)接收更新。
- 安全性: 支持DTLS(Datagram Transport Layer Security)加密。
- RESTful架構(gòu): 使用HTTP方法(GET, POST, PUT, DELETE),便于與現(xiàn)有Web服務(wù)集成。
Californium的核心組件
- CoapClient: 用于創(chuàng)建CoAP客戶端,發(fā)送請(qǐng)求并處理響應(yīng)。
- CoapServer: 用于創(chuàng)建CoAP服務(wù)器,處理來自客戶端的請(qǐng)求。
- CoapResource: 定義CoAP資源,處理特定路徑上的請(qǐng)求。
- CoapExchange: 提供請(qǐng)求和響應(yīng)的上下文,便于處理具體業(yè)務(wù)邏輯。
代碼實(shí)操
<!-- Spring Boot Web Dependency -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Californium Spring Boot Starter -->
<dependency>
<groupId>org.eclipse.californium</groupId>
<artifactId>californium-spring-boot-starter-server</artifactId>
<version>2.6.0</version>
</dependency>
<!-- Spring Data JPA for database operations -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- MySQL Driver -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
application.properties
# MySQL 數(shù)據(jù)庫配置
spring.datasource.url=jdbc:mysql://localhost:3306/iot_db?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=rootpassword
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# Hibernate 配置
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
Device實(shí)體類
package com.example.coapserver.entity;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
publicclass Device {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; // 設(shè)備ID,自增主鍵
private String deviceId; // 設(shè)備唯一標(biāo)識(shí)符
private String type; // 設(shè)備類型
privatedouble temperature; // 溫度數(shù)據(jù)
privateboolean active; // 設(shè)備是否激活
// Getter 和 Setter 方法
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public double getTemperature() {
return temperature;
}
public void setTemperature(double temperature) {
this.temperature = temperature;
}
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
}
倉(cāng)庫接口
package com.example.coapserver.repository;
import com.example.coapserver.entity.Device;
import org.springframework.data.jpa.repository.JpaRepository;
public interface DeviceRepository extends JpaRepository<Device, Long> {
Device findByDeviceId(String deviceId); // 根據(jù)設(shè)備ID查找設(shè)備
}
Controller
package com.example.coapserver.controller;
import com.example.coapserver.entity.Device;
import com.example.coapserver.repository.DeviceRepository;
import org.eclipse.californium.core.CoapHandler;
import org.eclipse.californium.core.CoapResponse;
import org.eclipse.californium.spring.annotation.CoapController;
import org.eclipse.californium.spring.annotation.CoapGetMapping;
import org.eclipse.californium.spring.annotation.CoapObserveRelation;
import org.eclipse.californium.spring.annotation.CoapPutMapping;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
@RestController
@CoapController
@RequestMapping("/api")
publicclass SensorDataController {
privatestaticfinal Logger logger = LoggerFactory.getLogger(SensorDataController.class);
@Autowired
private DeviceRepository deviceRepository; // 注入設(shè)備倉(cāng)庫
// 存儲(chǔ)傳感器數(shù)據(jù)的并發(fā)哈希映射
private ConcurrentHashMap<String, Double> sensorDataMap = new ConcurrentHashMap<>();
private AtomicInteger observeCounter = new AtomicInteger(0); // 觀察計(jì)數(shù)器
/**
* 注冊(cè)新設(shè)備
*
* @param device 要注冊(cè)的設(shè)備對(duì)象
* @return 注冊(cè)結(jié)果
*/
@PostMapping("/register")
public ResponseEntity<String> registerDevice(@RequestBody Device device) {
if (deviceRepository.findByDeviceId(device.getDeviceId()) != null) {
returnnew ResponseEntity<>("設(shè)備已注冊(cè)", HttpStatus.BAD_REQUEST);
}
device.setActive(true);
deviceRepository.save(device);
logger.info("注冊(cè)設(shè)備: {}", device.getDeviceId());
returnnew ResponseEntity<>("設(shè)備注冊(cè)成功", HttpStatus.CREATED);
}
/**
* 更新傳感器數(shù)據(jù)
*
* @param sensorId 傳感器ID
* @param payload 數(shù)據(jù)負(fù)載(溫度值)
*/
@CoapPutMapping("/sensors/{sensorId}")
public void updateSensorData(@PathVariable String sensorId, byte[] payload) {
String dataStr = new String(payload);
try {
double data = Double.parseDouble(dataStr);
Optional<Device> deviceOpt = Optional.ofNullable(deviceRepository.findByDeviceId(sensorId));
if (deviceOpt.isPresent()) {
Device device = deviceOpt.get();
device.setTemperature(data);
deviceRepository.save(device);
sensorDataMap.put(sensorId, data);
logger.info("收到傳感器 {} 的數(shù)據(jù): {}", sensorId, data);
checkAndAlert(sensorId, data);
observeCounter.incrementAndGet(); // 觸發(fā)觀察者通知
} else {
logger.warn("未知的傳感器ID: {}", sensorId);
}
} catch (NumberFormatException e) {
logger.error("傳感器 {} 的數(shù)據(jù)格式無效: {}", sensorId, dataStr);
}
}
/**
* 獲取傳感器數(shù)據(jù)
*
* @param sensorId 傳感器ID
* @return 傳感器數(shù)據(jù)
*/
@CoapGetMapping("/sensors/{sensorId}")
public String getSensorData(@PathVariable String sensorId) {
return sensorDataMap.getOrDefault(sensorId, "無數(shù)據(jù)").toString();
}
/**
* 提供一個(gè)可觀察的資源,用于實(shí)時(shí)訂閱傳感器狀態(tài)的變化
*
* @return 觀察計(jì)數(shù)器值
*/
@CoapObserveRelation
@CoapGetMapping("/observe")
public String observeSensors() {
int count = observeCounter.get();
logger.info("觀察傳感器,計(jì)數(shù)器: {}", count);
return String.valueOf(count); // 返回計(jì)數(shù)器值以觸發(fā)觀察者通知
}
/**
* 獲取所有已注冊(cè)的設(shè)備信息
*
* @return 設(shè)備列表
*/
@GetMapping("/devices")
public List<Device> getAllDevices() {
return deviceRepository.findAll();
}
/**
* 檢查溫度并觸發(fā)警報(bào)
*
* @param sensorId 傳感器ID
* @param temperature 溫度值
*/
private void checkAndAlert(String sensorId, double temperature) {
if (temperature > 30.0) {
logger.warn("高溫警報(bào):傳感器 {} 的溫度為 {}°C", sensorId, temperature);
// 在這里可以添加發(fā)送警報(bào)的通知邏輯
}
}
}
Application
package com.example.coapserver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class CoapServerApplication {
public static void main(String[] args) {
SpringApplication.run(CoapServerApplication.class, args);
}
}
測(cè)試
為了測(cè)試CoAP協(xié)議,我們可以使用Californium提供的命令行工具來發(fā)送CoAP請(qǐng)求。
我已經(jīng)安裝Californium CLI工具。你也可以從Californium GitHub倉(cāng)庫 (https://github.com/eclipse/californium)下載并編譯。很簡(jiǎn)單的!
更新傳感器數(shù)據(jù)
cf-cli put coap://localhost:5683/api/sensors/sensor1 --payload "25.5"
輸出:
Sending PUT request to coap://localhost:5683/api/sensors/sensor1
Response from coap://localhost:5683/api/sensors/sensor1:
Code: 2.04 Changed
Payload:
獲取傳感器數(shù)據(jù)
cf-cli get coap://localhost:5683/api/sensors/sensor1
輸出:
Sending GET request to coap://localhost:5683/api/sensors/sensor1
Response from coap://localhost:5683/api/sensors/sensor1:
Code: 2.05 Content
Options: [Content-Format:text/plain]
Payload: 25.5