修复投影仪控制
This commit is contained in:
@@ -3,13 +3,10 @@ package common
|
||||
import "sync"
|
||||
|
||||
type CtrlWait struct {
|
||||
// 用于暂停的chan
|
||||
P chan struct{}
|
||||
// 用于恢复的chan
|
||||
R chan struct{}
|
||||
C chan int8
|
||||
|
||||
// 状态
|
||||
s bool
|
||||
|
||||
m sync.RWMutex
|
||||
}
|
||||
|
||||
@@ -18,7 +15,7 @@ func (c *CtrlWait) Pause() {
|
||||
c.m.RLock()
|
||||
defer c.m.RUnlock()
|
||||
if c.s {
|
||||
c.P <- struct{}{}
|
||||
c.C <- 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +24,7 @@ func (c *CtrlWait) Resume() {
|
||||
c.m.RLock()
|
||||
defer c.m.RUnlock()
|
||||
if c.s {
|
||||
c.R <- struct{}{}
|
||||
c.C <- 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,8 +43,7 @@ func (c *CtrlWait) Close() {
|
||||
// NewCtrlWait 创建一个控制等待
|
||||
func NewCtrlWait() *CtrlWait {
|
||||
return &CtrlWait{
|
||||
P: make(chan struct{}),
|
||||
R: make(chan struct{}),
|
||||
C: make(chan int8),
|
||||
s: false,
|
||||
}
|
||||
}
|
||||
|
||||
53
internal/common/pause_sub.go
Normal file
53
internal/common/pause_sub.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package common
|
||||
|
||||
import "sync"
|
||||
|
||||
type PauseSub struct {
|
||||
ctrl *CtrlWait
|
||||
// 回调函数
|
||||
items []chan int8
|
||||
m sync.RWMutex
|
||||
}
|
||||
|
||||
// Add 添加一个暂停项
|
||||
func (p *PauseSub) Add(item chan int8) {
|
||||
p.m.Lock()
|
||||
defer p.m.Unlock()
|
||||
p.items = append(p.items, item)
|
||||
}
|
||||
|
||||
// Remove 移除一个暂停项
|
||||
func (p *PauseSub) Remove(item chan int8) {
|
||||
p.m.Lock()
|
||||
defer p.m.Unlock()
|
||||
for i, v := range p.items {
|
||||
if v == item {
|
||||
p.items = append(p.items[:i], p.items[i+1:]...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run 开始监听
|
||||
func (p *PauseSub) Run() {
|
||||
p.ctrl.Open()
|
||||
defer p.ctrl.Close()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-p.ctrl.C:
|
||||
go func() {
|
||||
p.m.RLock()
|
||||
defer p.m.RUnlock()
|
||||
for _, item := range p.items {
|
||||
item <- 1
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func NewPauseSub(c *CtrlWait) *PauseSub {
|
||||
return &PauseSub{
|
||||
ctrl: c,
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"game-driver/internal/common"
|
||||
"game-driver/leaf"
|
||||
"go.uber.org/zap"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func Pause(ctrl *common.CtrlWait) leaf.HandlerFunc {
|
||||
return func(c *leaf.Context) {
|
||||
var cancel context.CancelFunc
|
||||
|
||||
// 保存原始的 Context
|
||||
originalCtx := c.Context
|
||||
|
||||
// 获取锚点
|
||||
holdPoint := c.Hold()
|
||||
|
||||
// 等待组
|
||||
var wait sync.WaitGroup
|
||||
defer wait.Wait()
|
||||
|
||||
run := true
|
||||
|
||||
wait.Add(1)
|
||||
go func() {
|
||||
defer wait.Done()
|
||||
zap.S().Infoln("待机控制器")
|
||||
|
||||
ctrl.Open()
|
||||
defer ctrl.Close()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-originalCtx.Done():
|
||||
cancel()
|
||||
zap.S().Infoln("待机控制器监听结束")
|
||||
return
|
||||
case <-ctrl.R:
|
||||
{
|
||||
zap.S().Infoln("待机控制器 Resume 触发")
|
||||
c.Context = originalCtx
|
||||
run = true
|
||||
}
|
||||
case <-ctrl.P:
|
||||
{
|
||||
zap.S().Infoln("待机控制器 Pause 触发")
|
||||
run = false
|
||||
cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-originalCtx.Done():
|
||||
return
|
||||
default:
|
||||
if run {
|
||||
cancel = leaf.WithCancel(c)
|
||||
c.Resume(holdPoint)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
40
internal/routes/standby/audio.go
Normal file
40
internal/routes/standby/audio.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package standby
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"game-driver/internal/schema"
|
||||
"game-driver/pkg/audio"
|
||||
"game-driver/pkg/utils"
|
||||
"github.com/gopxl/beep/v2/speaker"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func Audio(item schema.WaitItemModel) func(c context.Context) error {
|
||||
return func(c context.Context) error {
|
||||
data, err := utils.LinkAudio(item.Data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("音频数据获取异常: %w", err)
|
||||
}
|
||||
if data == nil {
|
||||
return fmt.Errorf("音频数据获取为空")
|
||||
}
|
||||
|
||||
zap.S().Infoln("播放待机音乐")
|
||||
defer zap.S().Infoln("结束待机音乐")
|
||||
|
||||
ctrl, closer, e := audio.PlayBgmMP3(data)
|
||||
defer closer()
|
||||
if e != nil {
|
||||
return fmt.Errorf("播放待机音乐异常: %w", e)
|
||||
}
|
||||
|
||||
<-c.Done()
|
||||
|
||||
speaker.Lock()
|
||||
ctrl.Streamer = nil
|
||||
speaker.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
35
internal/routes/standby/pjlink.go
Normal file
35
internal/routes/standby/pjlink.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package standby
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"game-driver/config/wait"
|
||||
"game-driver/internal/schema"
|
||||
"game-driver/pkg/pjlink"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func PJLink(_ schema.WaitItemModel) func(c context.Context) error {
|
||||
return func(c context.Context) error {
|
||||
cfg := (wait.C).(wait.PJLink)
|
||||
pjc := pjlink.NewClient(cfg.Ip, cfg.Port, cfg.Password, cfg.Id)
|
||||
|
||||
zap.S().Infoln("打开待机投影仪")
|
||||
resp, err := pjc.PowerOn()
|
||||
if err != nil {
|
||||
return fmt.Errorf("打开投影仪异常: %w", err)
|
||||
}
|
||||
zap.S().Infoln("投影仪返回报文:", resp)
|
||||
|
||||
<-c.Done()
|
||||
|
||||
zap.S().Infoln("关闭待机投影仪")
|
||||
resp, err = pjc.PowerOff()
|
||||
if err != nil {
|
||||
return fmt.Errorf("关闭投影仪异常: %w", err)
|
||||
}
|
||||
zap.S().Infoln("投影仪返回报文:", resp)
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
28
internal/routes/standby/relay.go
Normal file
28
internal/routes/standby/relay.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package standby
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"game-driver/internal/schema"
|
||||
"game-driver/pkg/relay"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func Relay(item schema.WaitItemModel) func(c context.Context) error {
|
||||
return func(c context.Context) error {
|
||||
r, err := relay.New(item.Data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("继电器初始化异常: %w", err)
|
||||
}
|
||||
defer r.Close()
|
||||
|
||||
zap.S().Infoln("待机继电器供电")
|
||||
defer zap.S().Infoln("待机继电器断电")
|
||||
|
||||
_ = r.On(0)
|
||||
<-c.Done()
|
||||
_ = r.Off(0)
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
32
internal/routes/standby/tts.go
Normal file
32
internal/routes/standby/tts.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package standby
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"game-driver/internal/schema"
|
||||
"game-driver/pkg/audio"
|
||||
"game-driver/pkg/tts"
|
||||
"go.uber.org/zap"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TTS(item schema.WaitItemModel) func(c context.Context) error {
|
||||
return func(c context.Context) error {
|
||||
reader, err := tts.DefaultTTS.Get(item.Data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("语音合成异常: %w", err)
|
||||
}
|
||||
|
||||
zap.S().Infoln("播放待机 TTS 语音")
|
||||
defer zap.S().Infoln("结束待机 TTS 语音")
|
||||
|
||||
for {
|
||||
audio.PlayWav(c, reader)
|
||||
select {
|
||||
case <-c.Done():
|
||||
return nil
|
||||
case <-time.After(time.Duration(item.Interval) * time.Second):
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
38
internal/routes/standby/video.go
Normal file
38
internal/routes/standby/video.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package standby
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"game-driver/internal/schema"
|
||||
"game-driver/pkg/utils"
|
||||
"game-driver/pkg/video"
|
||||
"go.uber.org/zap"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Video(item schema.WaitItemModel) func(c context.Context) error {
|
||||
return func(c context.Context) error {
|
||||
local, err := utils.LinkVideo(item.Data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("视频文件获取异常: %w", err)
|
||||
}
|
||||
|
||||
zap.S().Infoln("播放待机视频")
|
||||
defer zap.S().Infoln("结束待机视频")
|
||||
|
||||
utils.BlankOpen()
|
||||
defer utils.BlankClose()
|
||||
|
||||
for {
|
||||
err := video.Play(c, local)
|
||||
if err != nil {
|
||||
return fmt.Errorf("视频播放异常: %w", err)
|
||||
}
|
||||
select {
|
||||
case <-c.Done():
|
||||
return nil
|
||||
case <-time.After(time.Duration(item.Interval) * time.Second):
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
22
internal/routes/standby/web.go
Normal file
22
internal/routes/standby/web.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package standby
|
||||
|
||||
import (
|
||||
"context"
|
||||
"game-driver/internal/schema"
|
||||
"game-driver/pkg/browser"
|
||||
"game-driver/pkg/utils"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func Web(item schema.WaitItemModel) func(c context.Context) error {
|
||||
return func(c context.Context) error {
|
||||
zap.S().Infoln("打开待机网页")
|
||||
|
||||
// 控制背光
|
||||
utils.BlankOpen()
|
||||
defer utils.BlankClose()
|
||||
|
||||
browser.OpenApp(c, item.Data)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
66
internal/routes/standby_ctrl/pause.go
Normal file
66
internal/routes/standby_ctrl/pause.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package standby_ctrl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"game-driver/internal/common"
|
||||
"go.uber.org/zap"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func Pause(ps *common.PauseSub, isPause bool, play func(c context.Context) error) func(c context.Context) error {
|
||||
return func(c context.Context) error {
|
||||
var cancel context.CancelFunc
|
||||
run := true
|
||||
|
||||
if isPause {
|
||||
p := make(chan int8)
|
||||
defer close(p)
|
||||
|
||||
ps.Add(p)
|
||||
defer ps.Remove(p)
|
||||
|
||||
zap.S().Infoln("待机控制器")
|
||||
defer zap.S().Infoln("待机控制器结束")
|
||||
|
||||
// 等待组
|
||||
var wait sync.WaitGroup
|
||||
defer wait.Wait()
|
||||
|
||||
wait.Add(1)
|
||||
go func() {
|
||||
defer wait.Done()
|
||||
for {
|
||||
select {
|
||||
case <-c.Done():
|
||||
return
|
||||
case v := <-p:
|
||||
if v == 1 {
|
||||
zap.S().Infoln("待机控制器 Pause 触发")
|
||||
run = false
|
||||
cancel()
|
||||
} else {
|
||||
zap.S().Infoln("待机控制器 Resume 触发")
|
||||
run = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-c.Done():
|
||||
return nil
|
||||
default:
|
||||
if run {
|
||||
nc, cc := context.WithCancel(c)
|
||||
cancel = cc
|
||||
err := play(nc)
|
||||
if err != nil {
|
||||
zap.S().Infoln("执行后续操作异常: ", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
91
internal/routes/standby_ctrl/time.go
Normal file
91
internal/routes/standby_ctrl/time.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package standby_ctrl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/go-pkgz/cronrange"
|
||||
"go.uber.org/zap"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Time 时间控制器
|
||||
func Time(rootRules []cronrange.Rule, cron string, play func(c context.Context) error) func(c context.Context) error {
|
||||
// 设定默认时间规则
|
||||
if cron == "" {
|
||||
cron = "* * * *"
|
||||
}
|
||||
|
||||
rules, err := cronrange.Parse(cron)
|
||||
if err != nil {
|
||||
zap.S().Errorln("解析时间规则异常: ", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
return func(c context.Context) error {
|
||||
a := make(chan bool)
|
||||
defer close(a)
|
||||
|
||||
// 等待组
|
||||
var waitGroup sync.WaitGroup
|
||||
defer waitGroup.Wait()
|
||||
|
||||
ticker := time.NewTicker(time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
waitGroup.Add(1)
|
||||
go func() {
|
||||
defer waitGroup.Done()
|
||||
for {
|
||||
select {
|
||||
case <-c.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
if cronrange.Match(rules, time.Now()) && cronrange.Match(rootRules, time.Now()) {
|
||||
a <- true
|
||||
} else {
|
||||
a <- false
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
var cancel context.CancelFunc
|
||||
var m sync.Mutex
|
||||
for {
|
||||
select {
|
||||
case <-c.Done():
|
||||
if cancel != nil {
|
||||
cancel()
|
||||
cancel = nil
|
||||
}
|
||||
return nil
|
||||
case r := <-a:
|
||||
if r {
|
||||
if ok := m.TryLock(); ok {
|
||||
ctx, cc := context.WithCancel(context.TODO())
|
||||
cancel = cc
|
||||
waitGroup.Add(1)
|
||||
go func() {
|
||||
defer waitGroup.Done()
|
||||
defer m.Unlock()
|
||||
defer func() { cancel = nil }()
|
||||
|
||||
err := play(ctx)
|
||||
if err != nil {
|
||||
zap.S().Errorln("执行动作异常: ", err)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-time.After(time.Minute):
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
} else if cancel != nil {
|
||||
cancel()
|
||||
cancel = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,291 +2,85 @@ package routes
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"game-driver/config/wait"
|
||||
"game-driver/internal/common"
|
||||
"game-driver/internal/middleware"
|
||||
"game-driver/internal/routes/standby"
|
||||
"game-driver/internal/routes/standby_ctrl"
|
||||
"game-driver/internal/schema"
|
||||
"game-driver/leaf"
|
||||
"game-driver/pkg/audio"
|
||||
"game-driver/pkg/browser"
|
||||
"game-driver/pkg/pjlink"
|
||||
"game-driver/pkg/relay"
|
||||
"game-driver/pkg/tts"
|
||||
"game-driver/pkg/utils"
|
||||
"game-driver/pkg/video"
|
||||
"github.com/go-pkgz/cronrange"
|
||||
"github.com/gopxl/beep/v2/speaker"
|
||||
"go.uber.org/zap"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
func runAction(c *leaf.Context, item schema.WaitItemModel, rootRules []cronrange.Rule, play func(c context.Context, item schema.WaitItemModel) error) {
|
||||
// 设定默认时间规则
|
||||
if item.Cron == "" {
|
||||
item.Cron = "* * * *"
|
||||
}
|
||||
func WaitAction(ctrl *common.CtrlWait) leaf.HandlerFunc {
|
||||
ps := common.NewPauseSub(ctrl)
|
||||
|
||||
rules, err := cronrange.Parse(item.Cron)
|
||||
if err != nil {
|
||||
zap.S().Errorln("解析时间规则异常: ", err)
|
||||
return
|
||||
}
|
||||
return func(c *leaf.Context) {
|
||||
payload := leaf.Value[*schema.WaitModel](c, middleware.PayloadJSONKey)
|
||||
|
||||
a := make(chan bool)
|
||||
defer close(a)
|
||||
|
||||
// 等待组
|
||||
var wait sync.WaitGroup
|
||||
defer wait.Wait()
|
||||
|
||||
ticker := time.NewTicker(time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
wait.Add(1)
|
||||
go func() {
|
||||
defer wait.Done()
|
||||
for {
|
||||
select {
|
||||
case <-c.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
if cronrange.Match(rules, time.Now()) && cronrange.Match(rootRules, time.Now()) {
|
||||
a <- true
|
||||
} else {
|
||||
a <- false
|
||||
}
|
||||
}
|
||||
// 设定默认时间规则,ctrl
|
||||
if payload.Cron == "" {
|
||||
payload.Cron = "* * * *"
|
||||
}
|
||||
}()
|
||||
|
||||
var cancel context.CancelFunc
|
||||
var m sync.Mutex
|
||||
for {
|
||||
select {
|
||||
case <-c.Done():
|
||||
if cancel != nil {
|
||||
cancel()
|
||||
}
|
||||
return
|
||||
case r := <-a:
|
||||
if r {
|
||||
if ok := m.TryLock(); ok {
|
||||
ctx, cc := context.WithCancel(context.TODO())
|
||||
cancel = cc
|
||||
wait.Add(1)
|
||||
go func() {
|
||||
defer wait.Done()
|
||||
defer m.Unlock()
|
||||
defer func() { cancel = nil }()
|
||||
|
||||
err := play(ctx, item)
|
||||
if err != nil {
|
||||
zap.S().Errorln("执行动作异常: ", err)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-time.After(time.Minute):
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
} else if cancel != nil {
|
||||
cancel()
|
||||
cancel = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func WaitAction(c *leaf.Context) {
|
||||
payload := leaf.Value[*schema.WaitModel](c, middleware.PayloadJSONKey)
|
||||
|
||||
// 设定默认时间规则
|
||||
if payload.Cron == "" {
|
||||
payload.Cron = "* * * *"
|
||||
}
|
||||
|
||||
rules, err := cronrange.Parse(payload.Cron)
|
||||
if err != nil {
|
||||
zap.S().Errorln("解析时间规则异常: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 等待组
|
||||
var wait sync.WaitGroup
|
||||
defer wait.Wait()
|
||||
for _, item := range payload.Items {
|
||||
switch item.Type {
|
||||
case schema.WaitAudio:
|
||||
// 执行音乐播放
|
||||
wait.Add(1)
|
||||
go func() {
|
||||
defer wait.Done()
|
||||
runAction(c, item, rules, audioAction)
|
||||
}()
|
||||
case schema.WaitTTS:
|
||||
// 执行TTS播放
|
||||
wait.Add(1)
|
||||
go func() {
|
||||
defer wait.Done()
|
||||
runAction(c, item, rules, ttsAction)
|
||||
}()
|
||||
case schema.WaitRelay:
|
||||
// 执行继电器供电
|
||||
wait.Add(1)
|
||||
go func() {
|
||||
defer wait.Done()
|
||||
runAction(c, item, rules, relayAction)
|
||||
}()
|
||||
case schema.WaitVideo:
|
||||
// 执行视频播放
|
||||
wait.Add(1)
|
||||
go func() {
|
||||
defer wait.Done()
|
||||
runAction(c, item, rules, videoAction)
|
||||
}()
|
||||
case schema.WaitWeb:
|
||||
// 执行网页打开
|
||||
wait.Add(1)
|
||||
go func() {
|
||||
defer wait.Done()
|
||||
runAction(c, item, rules, webAction)
|
||||
}()
|
||||
case schema.WaitPJLink:
|
||||
// 执行投影仪打开
|
||||
wait.Add(1)
|
||||
go func() {
|
||||
defer wait.Done()
|
||||
runAction(c, item, rules, pjlinkAction)
|
||||
}()
|
||||
default:
|
||||
zap.S().Infof("不支持的类型: %d\n", item.Type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func audioAction(c context.Context, item schema.WaitItemModel) error {
|
||||
data, err := utils.LinkAudio(item.Data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("音频数据获取异常: %w", err)
|
||||
}
|
||||
if data == nil {
|
||||
return fmt.Errorf("音频数据获取为空")
|
||||
}
|
||||
|
||||
zap.S().Infoln("播放待机音乐")
|
||||
defer zap.S().Infoln("结束待机音乐")
|
||||
|
||||
ctrl, closer, e := audio.PlayBgmMP3(data)
|
||||
defer closer()
|
||||
if e != nil {
|
||||
return fmt.Errorf("播放待机音乐异常: %w", e)
|
||||
}
|
||||
|
||||
<-c.Done()
|
||||
|
||||
speaker.Lock()
|
||||
ctrl.Streamer = nil
|
||||
speaker.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ttsAction(c context.Context, item schema.WaitItemModel) error {
|
||||
reader, err := tts.DefaultTTS.Get(item.Data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("语音合成异常: %w", err)
|
||||
}
|
||||
|
||||
zap.S().Infoln("播放待机 TTS 语音")
|
||||
defer zap.S().Infoln("结束待机 TTS 语音")
|
||||
|
||||
for {
|
||||
audio.PlayWav(c, reader)
|
||||
select {
|
||||
case <-c.Done():
|
||||
return nil
|
||||
case <-time.After(time.Duration(item.Interval) * time.Second):
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func relayAction(c context.Context, item schema.WaitItemModel) error {
|
||||
r, err := relay.New(item.Data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("继电器初始化异常: %w", err)
|
||||
}
|
||||
defer r.Close()
|
||||
|
||||
zap.S().Infoln("待机继电器供电")
|
||||
defer zap.S().Infoln("待机继电器断电")
|
||||
|
||||
_ = r.On(0)
|
||||
<-c.Done()
|
||||
_ = r.Off(0)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func videoAction(c context.Context, item schema.WaitItemModel) error {
|
||||
local, err := utils.LinkVideo(item.Data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("视频文件获取异常: %w", err)
|
||||
}
|
||||
|
||||
zap.S().Infoln("播放待机视频")
|
||||
defer zap.S().Infoln("结束待机视频")
|
||||
|
||||
utils.BlankOpen()
|
||||
defer utils.BlankClose()
|
||||
|
||||
for {
|
||||
err := video.Play(c, local)
|
||||
rules, err := cronrange.Parse(payload.Cron)
|
||||
if err != nil {
|
||||
return fmt.Errorf("视频播放异常: %w", err)
|
||||
zap.S().Errorln("解析时间规则异常: ", err)
|
||||
return
|
||||
}
|
||||
select {
|
||||
case <-c.Done():
|
||||
return nil
|
||||
case <-time.After(time.Duration(item.Interval) * time.Second):
|
||||
|
||||
// 等待组
|
||||
var waitGroup sync.WaitGroup
|
||||
defer waitGroup.Wait()
|
||||
|
||||
// 开启暂停监听
|
||||
waitGroup.Add(1)
|
||||
go func() {
|
||||
defer waitGroup.Done()
|
||||
ps.Run()
|
||||
}()
|
||||
|
||||
// 处理每个待机控制
|
||||
handleItem := func(title string, item schema.WaitItemModel, f func(c context.Context) error) {
|
||||
waitGroup.Add(1)
|
||||
go func() {
|
||||
defer waitGroup.Done()
|
||||
if f == nil {
|
||||
return
|
||||
}
|
||||
f = standby_ctrl.Time(rules, item.Cron, f)
|
||||
if f == nil {
|
||||
return
|
||||
}
|
||||
f = standby_ctrl.Pause(ps, item.Pause, f)
|
||||
if f == nil {
|
||||
return
|
||||
}
|
||||
e := f(c)
|
||||
if e != nil {
|
||||
zap.S().Errorf("%s异常: %s\n", title, e)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
for _, item := range payload.Items {
|
||||
switch item.Type {
|
||||
case schema.WaitAudio:
|
||||
handleItem("音乐待机控制", item, standby.Audio(item))
|
||||
case schema.WaitTTS:
|
||||
handleItem("TTS待机控制", item, standby.TTS(item))
|
||||
case schema.WaitRelay:
|
||||
handleItem("继电器待机控制", item, standby.Relay(item))
|
||||
case schema.WaitVideo:
|
||||
handleItem("视频待机控制", item, standby.Video(item))
|
||||
case schema.WaitWeb:
|
||||
handleItem("视频待机控制", item, standby.Web(item))
|
||||
case schema.WaitPJLink:
|
||||
handleItem("视频待机控制", item, standby.PJLink(item))
|
||||
default:
|
||||
zap.S().Infof("不支持的类型: %d\n", item.Type)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func webAction(c context.Context, item schema.WaitItemModel) error {
|
||||
zap.S().Infoln("打开待机网页")
|
||||
|
||||
// 控制背光
|
||||
utils.BlankOpen()
|
||||
defer utils.BlankClose()
|
||||
|
||||
browser.OpenApp(c, item.Data)
|
||||
return nil
|
||||
}
|
||||
|
||||
func pjlinkAction(c context.Context, _ schema.WaitItemModel) error {
|
||||
cfg := (wait.C).(wait.PJLink)
|
||||
pjc := pjlink.NewClient(cfg.Ip, cfg.Port, cfg.Password, cfg.Id)
|
||||
err := pjc.Connect()
|
||||
if err != nil {
|
||||
return fmt.Errorf("连接 PJLink 设备异常: %w", err)
|
||||
}
|
||||
defer pjc.Close()
|
||||
|
||||
zap.S().Infoln("打开待机投影仪")
|
||||
err = pjc.PowerOn()
|
||||
if err != nil {
|
||||
return fmt.Errorf("打开投影仪异常: %w", err)
|
||||
}
|
||||
|
||||
<-c.Done()
|
||||
|
||||
zap.S().Infoln("关闭待机投影仪")
|
||||
err = pjc.PowerOff()
|
||||
if err != nil {
|
||||
return fmt.Errorf("关闭投影仪异常: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ type WaitItemModel struct {
|
||||
Type WaitType `json:"type"`
|
||||
Data string `json:"data"`
|
||||
Interval int64 `json:"interval"`
|
||||
Pause bool `json:"pause"`
|
||||
}
|
||||
|
||||
type WaitModel struct {
|
||||
|
||||
@@ -154,8 +154,7 @@ func Run() {
|
||||
middleware.PayloadJSON[schema.WaitModel](),
|
||||
middleware.Unique(common.GlobalBgStopper),
|
||||
middleware.EmergencyStop(common.GlobalBgStopper),
|
||||
middleware.Pause(common.PassCtrl),
|
||||
routes.WaitAction,
|
||||
routes.WaitAction(common.PassCtrl),
|
||||
)
|
||||
// 处理指令
|
||||
router.RegisterHandler(topicPrefix+"command",
|
||||
|
||||
Reference in New Issue
Block a user