This commit is contained in:
2025-07-07 20:11:59 +08:00
parent ab0fdbc447
commit 06e3aa2eb3
2009 changed files with 193082 additions and 0 deletions

View File

@ -0,0 +1,17 @@
package camera
type LoginCamera struct {
URLToken string `json:"URLToken"`
TokenTimeout int64 `json:"TokenTimeout"`
}
type ChannelSnapReq struct {
Serial string `json:"serial" dc:"设备编号"`
Stime int64 `json:"stime" dc:"快照时间, 从录像截取指定时间的历史快照, now 表示取实时快照, 即抓图允许值: now, YYYYMMDDHHmmss"`
Format int64 `json:"format" dc:"stime 快照格式 允许值: jpeg, png"`
}
type ChannelSnapRes struct {
Serial string `json:"serial" dc:"设备编号"`
Stime int64 `json:"stime" dc:"快照时间, 从录像截取指定时间的历史快照, now 表示取实时快照, 即抓图允许值: now, YYYYMMDDHHmmss"`
Format int64 `json:"format" dc:"stime 快照格式 允许值: jpeg, png"`
}

View File

@ -0,0 +1,303 @@
package camera
import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/go-redis/redis/v8"
"github.com/gogf/gf/v2/crypto/gmd5"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gctx"
"github.com/tiger1103/gfast-cache/cache"
"github.com/tiger1103/gfast/v3/api/v1/common/coryCommon"
"github.com/tiger1103/gfast/v3/api/v1/system"
commonService "github.com/tiger1103/gfast/v3/internal/app/common/service"
"github.com/tiger1103/gfast/v3/internal/app/system/dao"
"github.com/tiger1103/gfast/v3/internal/app/system/model"
"github.com/tiger1103/gfast/v3/internal/app/system/model/do"
"github.com/tiger1103/gfast/v3/internal/app/system/service"
"github.com/tiger1103/gfast/v3/third/arithmetic/SpartaApi"
"io"
"log"
"os"
"path/filepath"
"strconv"
"strings"
"time"
)
// LoginCameraFunc 登录获取 身份凭证
func LoginCameraFunc(ctx context.Context) (token string) {
api, _ := g.Cfg().Get(ctx, "LiveGBS.safety.api")
acc, _ := g.Cfg().Get(ctx, "LiveGBS.safety.acc")
pas, _ := g.Cfg().Get(ctx, "LiveGBS.safety.pas")
key := "loginCamera"
//从缓存捞取key
prefix := g.Cfg().MustGet(ctx, "system.cache.prefix").String()
gfCache := cache.New(prefix)
get := commonService.Cache().Get(ctx, gfCache.CachePrefix+key)
if get != nil && get.String() != "" {
token = get.String()
return token
} else {
account := acc.String()
password := gmd5.MustEncryptString(pas.String())
uri := api.String() + "api/v1/login?username=" + account + "&password=" + password + "&url_token_only=true"
response, err := g.Client().Get(gctx.New(), uri)
if err != nil {
return
}
var lc *LoginCamera
err = json.Unmarshal([]byte(response.ReadAllString()), &lc)
if err != nil {
return
}
//将token存储到redis中tiken默认时间为秒实际计算为7天,(这里少100秒,防止token过期还存在redis中)
commonService.Cache().Set(ctx, key, lc.URLToken, time.Duration(lc.TokenTimeout-100)*time.Second)
token = lc.URLToken
return token
}
}
var Rdb *redis.Client
// camera.DYFunc()
// 发布小程序需要关闭 camera.DYFunc()
// DYFunc 连接redis
func DYFunc() {
ctx := gctx.New()
err := g.Try(ctx, func(ctx context.Context) {
fmt.Println("redis订阅已开启")
// 创建第一个 Redis 连接
address, _ := g.Cfg().Get(ctx, "LiveGBS.redis.address")
password, _ := g.Cfg().Get(ctx, "LiveGBS.redis.password")
// 创建一个 Redis 客户端连接
options := &redis.Options{
Addr: address.String(), // 替换为你的 Redis 地址和端口
Password: password.String(), // 替换为你的 Redis 密码
DB: 1, // 替换为你的 Redis 数据库索引
}
Rdb = redis.NewClient(options)
// 创建一个订阅频道
channelName := "device" // 替换为你要订阅的频道名
pubsub := Rdb.Subscribe(context.Background(), channelName)
// 处理订阅消息的 Goroutine
go func() {
for {
msg, err := pubsub.ReceiveMessage(context.Background())
if err != nil {
log.Println("Error receiving message:", err)
time.Sleep(time.Second) // 出错时等待一段时间后重试
continue
}
var strData = msg.Payload
log.Println("Received message:", strData)
//1、获取到数据然后查看是否''拼接(先不管拼接),不是''就直接操作数据库
split := strings.Split(strData, ":")
if len(split) < 2 {
onOrOff := strings.Split(split[0], " ")[1]
if strings.EqualFold(onOrOff, "on") {
onOrOff = "1"
} else {
onOrOff = "0"
}
_, err = dao.QianqiCamera.Ctx(ctx).Where("code", split[0]).Update(g.Map{"country_state": onOrOff})
//if err != nil {
// id, _ := result.LastInsertId()
// if id > 0 {
// dao.BusCameraChannel.Ctx(ctx).Where("country_id", id).Update(g.Map{"status": onOrOff})
// }
//}
}
time.Sleep(time.Second * 3)
}
}()
})
fmt.Println("订阅错误问题:", err)
}
// ChannelSnapFunc 快照
func ChannelSnapFunc(ctx context.Context, id int64, serial string, code string, projectId int64) (err error) {
//获取预制位,前提是 PresetEnable == true
pb, err := PeeeresettingBitFunc(gctx.New(), serial, code)
if err != nil {
return err
}
for _, pi := range pb.PresetItemList {
if pi.PresetEnable == true {
//0、预置位
err = PresettingBitFunc(ctx, serial, code, "goto", pi.PresetID, "")
//1、请求接口得到二进制数据
suffix := "png"
api, _ := g.Cfg().Get(ctx, "LiveGBS.safety.api")
tokens := LoginCameraFunc(ctx)
uri := api.String() + "api/v1/device/channelsnap?serial=" + serial + "&code=" + code + "&stime=now&format=" + suffix + "&token=" + tokens
response, err := g.Client().Get(gctx.New(), uri)
if err != nil {
return err
}
//2、生成时间文件夹生成文件名然后同一斜杠得到完成路径
ht := coryCommon.Helmet
str := coryCommon.Ynr(ht)
fn := coryCommon.FileName("helmet")
dir, err := os.Getwd()
str = dir + "/" + str + fn + "." + suffix
str = filepath.ToSlash(str)
//3、创建一个文件来保存图片数据将响应体中的图片数据复制到文件中
file, err := os.Create(str)
if err != nil {
err = errors.New("创建文件出错")
return err
}
// 创建一个缓冲区,用于读取数据(从 body 中读取数据)
var re = response
var by = re.Body
lenStr, err := io.Copy(file, by)
if err != nil {
err = errors.New("复制图片数据到文件出错")
return err
} else {
file.Close()
}
if lenStr < 10240 {
file.Close() // 关闭文件
os.Remove(str)
return err
}
//4、《斯巴达》调用算法接口圈出未带安全帽的人
req := SpartaApi.RecognizeReq{
CapUrl: str,
//RecType: "head smoke belt waste excavator Roller Truck_crane Loader Submersible_drilling_rig Sprinkler Truck_mounted_crane Truck",
RecType: "head smoke",
Async: "False",
CallBackUrl: "",
AreaHigh: "",
}
mp, flag, num, err := SpartaApi.CommonAlgorithmFunc(ctx, &req)
if err != nil {
os.Remove(str)
return err
}
////4、《ys7》调用算法接口圈出未带安全帽的人
//flag, num, err := ys7.InitYs7(str)
//if err != nil {
// os.Remove(str)
// return err
//}
//5、flag为true表示有违规数据
if flag {
// 使用range遍历map
mpkStr := ""
mpvStr := ""
for key, value := range mp {
mpkStr = mpkStr + key + ","
mpvStr = mpvStr + value + "、"
}
mpkStr = strings.TrimRight(mpkStr, ",")
mpvStr = strings.TrimRight(mpvStr, "、")
//5、生成数据存储到数据表中识别记录
path := strings.ReplaceAll(ht, "/resource/public/", coryCommon.GetWd)
currentTime := time.Now()
dateString := currentTime.Format("2006-01-02")
path = path + dateString + "/" + fn + "." + suffix
addReq := system.BusTourAddReq{
ProjectId: projectId,
TourCategory: "2",
TourType: "1",
Picture: path,
Describe: mpvStr,
Num: num,
TableName: dao.QianqiCamera.Table(),
TableId: id,
}
service.BusTour().Add(ctx, &addReq)
//6、生成数据存储到违规记录里面
var bvl model.BusViolationLevelInfoRes
err = dao.BusViolationLevel.Ctx(ctx).Where("tour_type", mpkStr).Fields("id,grade").Scan(&bvl)
recordAddReq := do.BusViolationRecord{
ProjectId: projectId,
LevelId: bvl.Id,
Level: bvl.Grade,
TourType: mpkStr,
DataSource: "camera",
//Picture: path,
//WxOrPc: "1",
}
dao.BusViolationRecord.Ctx(ctx).Insert(recordAddReq)
}
time.Sleep(20 * time.Second)
}
}
return err
}
/*
PresettingBitFunc 设备控制-预置位控制
serial: 国标号
code: 通道号
command: 指令
preset: 预置位编号
name: 预置位名称
*/
func PresettingBitFunc(ctx context.Context, serial string, code string, command string, preset int, name string) (err error) {
if name != "" && (name == "set" || name == "goto" || name == "remove") {
err = errors.New("控制指令允许值: set, goto, remove")
return err
}
if !(preset > 0 && preset <= 255) {
err = errors.New("预置位编号范围为1~255")
return err
}
tokens := LoginCameraFunc(ctx)
api, _ := g.Cfg().Get(ctx, "LiveGBS.safety.api")
uri := api.String() + "api/v1/control/preset?serial=" + serial +
"&code=" + code +
"&command=" + command +
"&preset=" + strconv.Itoa(preset) +
"&token=" + tokens
if name != "" {
uri = uri + "&name=" + name
}
g.Client().Get(gctx.New(), uri)
return err
}
func PeeeresettingBitFunc(ctx context.Context, serial string, code string) (pb *PeeeresettingBitEntity, err error) {
tokens := LoginCameraFunc(ctx)
api, _ := g.Cfg().Get(ctx, "LiveGBS.safety.api")
uri := api.String() + "api/v1/device/fetchpreset?serial=" + serial +
"&code=" + code +
"&token=" + tokens +
"&fill=false"
ft, errft := g.Client().Get(gctx.New(), uri)
var str = ft.ReadAllString()
err = json.Unmarshal([]byte(str), &pb)
if err != nil {
if strings.Contains(str, "offline") {
err = errors.New("当前设备不在线!")
} else if strings.Contains(str, "not found") {
err = errors.New("当前设备沒找到!")
} else {
err = errft
}
return
}
return
}
type PeeeresettingBitEntity struct {
DeviceID string `json:"DeviceID"`
Result string `json:"Result"`
SumNum int `json:"SumNum"`
PresetItemList []*PeeeresettingBitListEntity `json:"PresetItemList"`
}
type PeeeresettingBitListEntity struct {
PresetID int `json:"PresetID"`
PresetName string `json:"PresetName"`
PresetEnable bool `json:"PresetEnable"`
}