rain_monitor/em3395ty/scheduler.go
2025-07-12 17:41:49 +08:00

222 lines
6.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package em3395ty
import (
"database/sql"
"log"
"time"
)
// QueryInterval 查询间隔类型
type QueryInterval string
const (
// 预定义的查询间隔
IntervalHourly QueryInterval = "hourly" // 整点查询
IntervalThirtyMin QueryInterval = "30min" // 每30分钟
IntervalTenMin QueryInterval = "10min" // 每10分钟
IntervalThirtySec QueryInterval = "30sec" // 每30秒
IntervalTenSec QueryInterval = "10sec" // 每10秒
IntervalCustom QueryInterval = "custom" // 自定义间隔
)
type EM3395TYScheduler struct {
db *sql.DB
deviceIDs []string
accessToken string
tokenExpireAt time.Time
ticker *time.Ticker
stopChan chan struct{}
interval QueryInterval
customInterval time.Duration // 自定义间隔时间
}
// NewScheduler 创建一个新的EM3395TY调度器默认整点查询
func NewScheduler(db *sql.DB, deviceIDs []string) *EM3395TYScheduler {
return &EM3395TYScheduler{
db: db,
deviceIDs: deviceIDs,
stopChan: make(chan struct{}),
interval: IntervalHourly,
}
}
// SetQueryInterval 设置查询间隔
func (s *EM3395TYScheduler) SetQueryInterval(interval QueryInterval) {
s.interval = interval
log.Printf("EM3395TY设备查询间隔已设置为: %s", interval)
}
// SetCustomInterval 设置自定义查询间隔
func (s *EM3395TYScheduler) SetCustomInterval(duration time.Duration) {
s.interval = IntervalCustom
s.customInterval = duration
log.Printf("EM3395TY设备查询间隔已设置为自定义: %s", duration)
}
// Start 启动定时查询任务
func (s *EM3395TYScheduler) Start() {
log.Println("启动EM3395TY设备定时查询任务")
// 初始化设备信息
s.initDevices()
// 启动查询任务
go s.startQueryTask()
}
// Stop 停止定时查询任务
func (s *EM3395TYScheduler) Stop() {
if s.ticker != nil {
s.ticker.Stop()
}
close(s.stopChan)
log.Println("EM3395TY设备定时查询任务已停止")
}
// initDevices 初始化设备信息
func (s *EM3395TYScheduler) initDevices() {
// 获取访问令牌
token, err := GetAccessToken()
if err != nil {
log.Printf("获取访问令牌失败: %v", err)
return
}
s.accessToken = token
s.tokenExpireAt = time.Now().Add(1 * time.Hour) // 假设令牌有效期为1小时
// 检查每个设备是否存在于数据库中,如果不存在则查询设备信息并保存
for _, deviceID := range s.deviceIDs {
exists, err := CheckDeviceExists(s.db, deviceID)
if err != nil {
log.Printf("检查设备 %s 是否存在失败: %v", deviceID, err)
continue
}
if !exists {
log.Printf("设备 %s 不存在于数据库中,正在获取设备信息", deviceID)
deviceInfo, err := GetDeviceInfo(s.accessToken, deviceID)
if err != nil {
log.Printf("获取设备 %s 信息失败: %v", deviceID, err)
continue
}
_, err = SaveDeviceInfo(s.db, deviceInfo)
if err != nil {
log.Printf("保存设备 %s 信息失败: %v", deviceID, err)
continue
}
log.Printf("设备 %s 信息已保存到数据库", deviceID)
} else {
log.Printf("设备 %s 已存在于数据库中", deviceID)
}
}
}
// getIntervalDuration 获取查询间隔时间
func (s *EM3395TYScheduler) getIntervalDuration() time.Duration {
switch s.interval {
case IntervalHourly:
return 1 * time.Hour
case IntervalThirtyMin:
return 30 * time.Minute
case IntervalTenMin:
return 10 * time.Minute
case IntervalThirtySec:
return 30 * time.Second
case IntervalTenSec:
return 10 * time.Second
case IntervalCustom:
return s.customInterval
default:
return 1 * time.Hour
}
}
// startQueryTask 启动查询任务
func (s *EM3395TYScheduler) startQueryTask() {
interval := s.getIntervalDuration()
if s.interval == IntervalHourly {
// 对于整点查询,计算距离下一个整点的时间
now := time.Now()
nextHour := time.Date(now.Year(), now.Month(), now.Day(), now.Hour()+1, 0, 0, 0, now.Location())
duration := nextHour.Sub(now)
log.Printf("EM3395TY设备第一次查询将在 %s 后进行 (整点: %s)",
duration.String(), nextHour.Format("15:04:05"))
// 等待到下一个整点
timer := time.NewTimer(duration)
select {
case <-timer.C:
s.queryAllDevices()
case <-s.stopChan:
timer.Stop()
return
}
s.ticker = time.NewTicker(interval)
} else {
// 对于非整点查询,立即执行一次查询,然后按照间隔定时执行
log.Printf("EM3395TY设备查询任务已启动每 %s 查询一次", interval)
s.queryAllDevices()
s.ticker = time.NewTicker(interval)
}
// 循环执行查询任务
for {
select {
case <-s.ticker.C:
s.queryAllDevices()
case <-s.stopChan:
return
}
}
}
// queryAllDevices 查询所有设备的状态
func (s *EM3395TYScheduler) queryAllDevices() {
log.Println("执行EM3395TY设备查询任务")
// 检查令牌是否过期
if time.Now().After(s.tokenExpireAt) {
log.Println("访问令牌已过期,正在重新获取")
token, err := GetAccessToken()
if err != nil {
log.Printf("重新获取访问令牌失败: %v", err)
return
}
s.accessToken = token
s.tokenExpireAt = time.Now().Add(1 * time.Hour)
}
// 查询每个设备的状态
for _, deviceID := range s.deviceIDs {
log.Printf("正在查询设备 %s 的状态", deviceID)
deviceStatus, err := GetDeviceStatus(s.accessToken, deviceID)
if err != nil {
log.Printf("获取设备 %s 状态失败: %v", deviceID, err)
continue
}
// 保存设备状态到数据库
id, err := SaveDeviceStatus(s.db, deviceID, deviceStatus)
if err != nil {
log.Printf("保存设备 %s 状态失败: %v", deviceID, err)
continue
}
log.Printf("设备 %s 状态已保存ID=%d", deviceID, id)
// 打印部分关键数据
log.Printf("设备 %s 室内温度: %.1f℃, 室内湿度: %d%%, 室外温度: %.1f℃, 室外湿度: %d%%, 一小时降雨量: %.1fmm",
deviceID,
float64(deviceStatus.Result.TempCurrent)/10.0,
deviceStatus.Result.HumidityValue,
float64(deviceStatus.Result.TempCurrentExternal)/10.0,
deviceStatus.Result.HumidityOutdoor,
float64(deviceStatus.Result.Rain1h)/10.0)
}
}