diff --git a/config.yml b/config.yml index 6b3f841..653b377 100644 --- a/config.yml +++ b/config.yml @@ -62,7 +62,7 @@ task: # Lora 配置 lora: - mode: "lora_wan" # "lora_wan" or "lora_mesh" + mode: "lora_mesh" # "lora_wan" or "lora_mesh" lora_mesh: # 主节点串口 diff --git a/internal/app/webhook/placeholder_listener.go b/internal/app/webhook/placeholder_listener.go new file mode 100644 index 0000000..ffcf216 --- /dev/null +++ b/internal/app/webhook/placeholder_listener.go @@ -0,0 +1,30 @@ +package webhook + +import ( + "net/http" + + "git.huangwc.com/pig/pig-farm-controller/internal/infra/logs" +) + +// PlaceholderListener 是一个占位符, 用于在非 LoRaWAN 配置下满足 ListenHandler 接口 +type PlaceholderListener struct { + logger *logs.Logger +} + +// NewPlaceholderListener 创建一个新的 PlaceholderListener 实例 +// 它只打印一条日志, 表明 ChirpStack webhook 未被激活 +func NewPlaceholderListener(logger *logs.Logger) ListenHandler { + logger.Info("当前配置非 LoRaWAN, ChirpStack webhook 监听器未激活。") + return &PlaceholderListener{ + logger: logger, + } +} + +// Handler 返回一个不执行任何操作的 http.HandlerFunc +// 理论上, 在占位符生效的模式下, 这个 Handler 不应该被调用 +func (p *PlaceholderListener) Handler() http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + p.logger.Warn("PlaceholderListener 的 Handler 被调用, 这通常是意料之外的。") + w.WriteHeader(http.StatusNotImplemented) + } +} diff --git a/internal/core/application.go b/internal/core/application.go index 25e596f..9b2bf5b 100644 --- a/internal/core/application.go +++ b/internal/core/application.go @@ -20,6 +20,7 @@ import ( "git.huangwc.com/pig/pig-farm-controller/internal/infra/logs" "git.huangwc.com/pig/pig-farm-controller/internal/infra/models" "git.huangwc.com/pig/pig-farm-controller/internal/infra/repository" + "git.huangwc.com/pig/pig-farm-controller/internal/infra/transport" "git.huangwc.com/pig/pig-farm-controller/internal/infra/transport/lora" ) @@ -37,6 +38,9 @@ type Application struct { executionLogRepo repository.ExecutionLogRepository pendingCollectionRepo repository.PendingCollectionRepository analysisPlanTaskManager *task.AnalysisPlanTaskManager + + // Lora Mesh 监听器 + loraMeshCommunicator transport.Listener } // NewApplication 创建并初始化一个新的 Application 实例。 @@ -98,15 +102,27 @@ func NewApplication(configPath string) (*Application, error) { // 初始化审计服务 auditService := audit.NewService(userActionLogRepo, logger) - // 初始化设备上行监听器 - listenHandler := webhook.NewChirpStackListener(logger, sensorDataRepo, deviceRepo, areaControllerRepo, deviceCommandLogRepo, pendingCollectionRepo) + // --- 初始化 LoRa 相关组件 --- + var listenHandler webhook.ListenHandler + var comm transport.Communicator + var loraListener transport.Listener + + if cfg.Lora.Mode == config.LoraMode_LoRaWAN { + logger.Info("当前运行模式: lora_wan。初始化 ChirpStack 监听器和传输层。") + listenHandler = webhook.NewChirpStackListener(logger, sensorDataRepo, deviceRepo, areaControllerRepo, deviceCommandLogRepo, pendingCollectionRepo) + comm = lora.NewChirpStackTransport(cfg.ChirpStack, logger) + loraListener = lora.NewPlaceholderTransport(logger) + } else { + logger.Info("当前运行模式: lora_mesh。初始化 LoRa Mesh 传输层和占位符监听器。") + listenHandler = webhook.NewPlaceholderListener(logger) + tp := lora.NewLoRaMeshUartPassthroughTransport(cfg.LoraMesh, logger) + loraListener = tp + comm = tp + } // 初始化计划触发器管理器 analysisPlanTaskManager := task.NewAnalysisPlanTaskManager(planRepo, pendingTaskRepo, executionLogRepo, logger) - // 初始化设备通信器 (纯粹的通信客户端) - comm := lora.NewChirpStackTransport(cfg.ChirpStack, logger) - // 初始化通用设备服务 generalDeviceService := device.NewGeneralDeviceService( deviceRepo, @@ -160,6 +176,7 @@ func NewApplication(configPath string) (*Application, error) { executionLogRepo: executionLogRepo, pendingCollectionRepo: pendingCollectionRepo, analysisPlanTaskManager: analysisPlanTaskManager, + loraMeshCommunicator: loraListener, } return app, nil @@ -169,6 +186,11 @@ func NewApplication(configPath string) (*Application, error) { func (app *Application) Start() error { app.Logger.Info("应用启动中...") + // -- 启动 LoRa Mesh 监听器 + if err := app.loraMeshCommunicator.Listen(); err != nil { + return fmt.Errorf("启动 LoRa Mesh 监听器失败: %w", err) + } + // --- 清理待采集任务 --- if err := app.initializePendingCollections(); err != nil { // 这是一个非致命错误,记录它,但应用应继续启动 @@ -216,6 +238,11 @@ func (app *Application) Stop() error { app.Logger.Errorw("数据库连接断开失败", "error", err) } + // 关闭 LoRa Mesh 监听器 + if err := app.loraMeshCommunicator.Stop(); err != nil { + app.Logger.Errorw("LoRa Mesh 监听器关闭失败", "error", err) + } + // 刷新日志缓冲区 _ = app.Logger.Sync() diff --git a/internal/infra/config/config.go b/internal/infra/config/config.go index 966f402..29f489a 100644 --- a/internal/infra/config/config.go +++ b/internal/infra/config/config.go @@ -136,9 +136,16 @@ type TaskConfig struct { NumWorkers int `yaml:"num_workers"` } +type LoraMode string + +const ( + LoraMode_LoRaWAN LoraMode = "lora_wan" + LoraMode_LoRaMesh LoraMode = "lora_mesh" +) + // LoraConfig 代表Lora配置 type LoraConfig struct { - Mode string `yaml:"mode"` + Mode LoraMode `yaml:"mode"` } // LoraMeshConfig 代表Lora Mesh配置 diff --git a/internal/infra/transport/lora/lora_mesh_uart_passthrough_transport.go b/internal/infra/transport/lora/lora_mesh_uart_passthrough_transport.go new file mode 100644 index 0000000..b0eab7b --- /dev/null +++ b/internal/infra/transport/lora/lora_mesh_uart_passthrough_transport.go @@ -0,0 +1,33 @@ +package lora + +import ( + "git.huangwc.com/pig/pig-farm-controller/internal/infra/config" + "git.huangwc.com/pig/pig-farm-controller/internal/infra/logs" + "git.huangwc.com/pig/pig-farm-controller/internal/infra/transport" +) + +// LoRaMeshUartPassthroughTransport 实现 transport.Communicator 接口, 用于 LoRa 网状网络 UART 透传 +type LoRaMeshUartPassthroughTransport struct { + // 在这里添加必要的字段 +} + +// NewLoRaMeshUartPassthroughTransport 创建一个新的 LoRaMeshUartPassthroughTransport +func NewLoRaMeshUartPassthroughTransport(config config.LoraMeshConfig, logger *logs.Logger) *LoRaMeshUartPassthroughTransport { + return &LoRaMeshUartPassthroughTransport{} +} + +// Send 将数据发送到指定的地址 +func (t *LoRaMeshUartPassthroughTransport) Send(address string, payload []byte) (*transport.SendResult, error) { + // TODO: 实现发送逻辑 + return nil, nil +} + +func (t *LoRaMeshUartPassthroughTransport) Listen() error { + //TODO implement me + panic("implement me") +} + +func (t *LoRaMeshUartPassthroughTransport) Stop() error { + //TODO implement me + panic("implement me") +} diff --git a/internal/infra/transport/lora/placeholder_transport.go b/internal/infra/transport/lora/placeholder_transport.go new file mode 100644 index 0000000..967b0b9 --- /dev/null +++ b/internal/infra/transport/lora/placeholder_transport.go @@ -0,0 +1,27 @@ +package lora + +import ( + "git.huangwc.com/pig/pig-farm-controller/internal/infra/logs" + "git.huangwc.com/pig/pig-farm-controller/internal/infra/transport" +) + +type PlaceholderTransport struct { + logger *logs.Logger +} + +func NewPlaceholderTransport(logger *logs.Logger) transport.Listener { + logger.Info("当前配置非 LoRaMesh, LoRaMesh UART 透传传输器未激活。") + return &PlaceholderTransport{ + logger: logger, + } +} + +func (p *PlaceholderTransport) Listen() error { + p.logger.Warnf("当前不是LoRa Mesh 模式, 这只是个占位监听器") + return nil +} + +func (p *PlaceholderTransport) Stop() error { + p.logger.Warnf("当前不是LoRa Mesh 模式, 占位监听器停止工作") + return nil +} diff --git a/internal/infra/transport/transport.go b/internal/infra/transport/transport.go index 648aaeb..aee61a8 100644 --- a/internal/infra/transport/transport.go +++ b/internal/infra/transport/transport.go @@ -13,3 +13,12 @@ type SendResult struct { // 调用方需要保存此 ID,以便后续关联 ACK 等事件。 MessageID string } + +// Listener 用于监听其他设备发送过来的数据 +type Listener interface { + // Listen 用于开始监听其他设备发送过来的数据 + Listen() error + + // Stop 用于停止监听 + Stop() error +}