1.定义日志
func InitAlarmModule() {
logFile, err := os.OpenFile("./alert.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
log.Panic("打开日志文件异常")
}
log.SetOutput(logFile)
log.SetFlags(log.Lshortfile | log.Ldate | log.Lmicroseconds))
}
2.基础信息
const (
rtuMinSize = 4
rtuMaxSize = 256
rtuExceptionSize = 5
tcpTimeout = 10 * time.Second
tcpIdleTimeout = 60 * time.Second
)
type Device struct {
DeviceId string //子设备id
ServerAddr string //服务地址
AccessToken string //子设备token
Interval int64 //触发时间间隔s
DeviceAddress uint8 //设备地址
FunctionCode uint8 //功能码
StartingAddress uint16 //起始地址
AddressNum uint16 //地址数量(地址数量返现,根据数据类型后面的数字除以2,比如int32-4的地址数量就是2)
Key string //属性名(如:temp,hum等)
DataType string //数据类型(3和6功能码的数据类型:int16-2 uint16-2 int32-4 uint32-4 int64-8(一个地址2字节));uint64在转换中会丢失精度,uint32在转float时候某些值也会丢失精度
VolumeType int //声音种类 1:语音 2:警戒音
}
type Command struct {
Code uint16 //0:delete, 1: start mp3, 2: start text, 3: stop
Priority uint16 //优先级
State uint16 //00H、01H代表设备打开;00H、02H代表警示灯打开;00H、03H代表设备和警示灯都打开
Volume uint16 //报警声音, 音量最高30
Tune uint16 //报警音调, 高8位为第几个文件夹,低8位为第几个语音(目前只支持一个文件夹)
PlayMode uint16 //0001 循环,0002 单曲
LightMode uint16 //01代表爆闪(当前设备不支持其它模式)
Sound uint16 //00: 女, 01:男
Saved uint16 //是否保存, 保存会更换报警音调。
Text string //报警文本
}
3.获取报警设备在线状态
//deviceId为可查询到的设备唯一标识,非设备本身id
func GetAlarmState(deviceId string) (online bool, err error) {
start := time.Now().UnixMicro()
mu.Lock()
defer mu.Unlock()
online = false
if deviceId == "" {
err = fmt.Errorf("alarm: get deviceId %s error", deviceId)
return
}
am, ok := AlarmConfigMap.Load(deviceId)
if ok == false {
err = fmt.Errorf("alarm: get deviceId %s error", deviceId)
return
}
time.Sleep(50 * time.Millisecond)
if am.(*AlarmHandler).conn != nil {
online = true
}
end := time.Now().UnixMicro()
fmt.Printf("获取报警器状态: %v, deviceId: %s, 耗时 %d micro seconds", online, deviceId, end-start)
return
}
4.发送指令
// Send sends data to server and ensures response length is greater than header length.
func (mb *AlarmHandler) Send(aduRequest []byte) (err error) {
mb.mu.Lock()
defer mb.mu.Unlock()
deviceId := mb.DeviceId
// Establish a new connection if not connected
if mb.conn == nil {
log.Printf("alarm: %s %s \n", deviceId, "conn error")
return
}
// Set write and read timeout
var timeout time.Time
if mb.Timeout > 0 {
timeout.Add(mb.Timeout)
}
if err = mb.conn.SetDeadline(timeout); err != nil {
log.Println("alarm: ", deviceId, "send error", err)
return
}
// Send data
log.Printf("alarm: %s sending % x\n", deviceId, aduRequest)
if _, err = mb.conn.Write(aduRequest); err != nil {
log.Printf("alarm: %s %s %v \n", deviceId, "send error", err)
//mb.close()
return
}
return
}
func (mb *AlarmHandler) Read() (aduResponse []byte, err error) {
mb.mu.Lock()
defer mb.mu.Unlock()
deviceId := mb.DeviceId
if mb.conn == nil {
return
}
// Set write and read timeout
var timeout time.Time
if mb.Timeout > 0 {
timeout = time.Now().Add(mb.Timeout)
}
if err = mb.conn.SetDeadline(timeout); err != nil {
log.Printf("alarm: %s %s %v\n", deviceId, "set timeout error", err)
return
}
mb.startCloseTimer()
var data [rtuMaxSize]byte
var length int
if length, err = mb.conn.Read(data[:rtuMaxSize]); err != nil {
log.Printf("alarm: %s %s %v\n", deviceId, "read error", err)
return
}
// Set timer to close when idle
mb.lastActivity = time.Now()
mb.resetCloseTimer()
aduResponse = data[:le