// windows  Linux系统通用
// 本代码使用的编译环境为:golang-go
// 运行指令:go run main.go
package main

import (
	"fmt"
	"os"
	"strings"
	"time"

	MQTT "github.com/eclipse/paho.mqtt.golang"
	"golang.org/x/text/encoding/simplifiedchinese"
	"golang.org/x/text/transform"
)

func utf8ToGB2312(str string) (string, error) {
	// GB2312编码器
	encoder := simplifiedchinese.GB18030.NewEncoder()

	// 使用转换器将UTF-8字符串转换为GB2312编码
	gb2312Bytes, _, err := transform.Bytes(encoder, []byte(str))
	if err != nil {
		return "", err
	}

	// 将转换后的字节切片转换为字符串
	gb2312Str := string(gb2312Bytes)
	return gb2312Str, nil
}

func main() {
	// 创建MQTT客户端配置
	opts := MQTT.NewClientOptions()
	opts.AddBroker("tcp://192.168.10.173:1883") // 使用你要连接的MQTT服务器地址和端口
	opts.SetClientID("mqtt-client")             // 设置客户端ID

	// 创建MQTT客户端
	client := MQTT.NewClient(opts)

	// 连接到MQTT服务器
	if token := client.Connect(); token.Wait() && token.Error() != nil {
		fmt.Println(token.Error())
		os.Exit(1)
	}

	// 0：DO 继电器输出接口
	// 1：DI 开关量输入接口
	// 2：AI 模拟量输入接口
	// 3：VO 语音输出接口
	// 4：PC 电脑开关机接口
	ExecType := 0

	fmt.Println("Connected to MQTT server")

	// 订阅回复主题
	replyTopic := "/user/update"
	client.Subscribe(replyTopic, 0, func(client MQTT.Client, msg MQTT.Message) {
		fmt.Printf("Received reply: %s\n", string(msg.Payload()))
	})

	// 发布问题到请求主题
	requestTopic := "/user/get"

	switch ExecType {
	case 0:
		fmt.Printf("DO继电器输出接口测试：")
		// 控制DO继电器输出接口OUT1吸合；发送指令：AT+STACH1=1\r\n
		sendCmd := "AT+STACH1=1\r\n"
		token := client.Publish(requestTopic, 0, false, sendCmd)
		token.Wait()
		fmt.Printf("SendCmd: %s\n", strings.Replace(sendCmd, "\r\n", "\\r\\n", -1))
		// 等待回复
		time.Sleep(1 * time.Second) // 等待一段时间来接收回复

		// 时间单位改成 秒；发送指令：AT+DLYUNIT=0\r\n
		sendCmd = "AT+DLYUNIT=0\r\n"
		token = client.Publish(requestTopic, 0, false, sendCmd)
		token.Wait()
		fmt.Printf("SendCmd: %s\n", strings.Replace(sendCmd, "\r\n", "\\r\\n", -1))
		// 等待回复
		time.Sleep(1 * time.Second) // 等待一段时间来接收回复

		// 控制DO继电器输出接口OUT1点动开，开启后延时5秒再关闭：AT+STACH1=3,5,100000,1000000\r\n
		sendCmd = "AT+STACH1=3,5,100000,1000000\r\n"
		token = client.Publish(requestTopic, 0, false, sendCmd)
		token.Wait()
		fmt.Printf("SendCmd: %s\n", strings.Replace(sendCmd, "\r\n", "\\r\\n", -1))
		// 等待回复
		time.Sleep(1 * time.Second) // 等待一段时间来接收回复

		// 控制DO继电器输出接口OUT1~OUT4间隔1秒轮流吸合：AT+DODLY=1,1,4,1,1\r\n
		sendCmd = "AT+DODLY=1,1,4,1,1\r\n"
		token = client.Publish(requestTopic, 0, false, sendCmd)
		token.Wait()
		fmt.Printf("SendCmd: %s\n", strings.Replace(sendCmd, "\r\n", "\\r\\n", -1))
		// 等待回复
		time.Sleep(1 * time.Second) // 等待一段时间来接收回复

		// 继电器OUT1每天早上8点定时吸合：AT+AUTOCONT=2,TASK1,[CYC:1],[T:3,0|1|2|3|4|5|6,08:00:00],[DO:0,1,1,100000,100000,1000000],[N:1,0]\r\n
		sendCmd = "AT+AUTOCONT=2,TASK1,[CYC:1],[T:3,0|1|2|3|4|5|6,08:00:00],[DO:0,1,1,100000,100000,1000000],[N:1,0]\r\n"
		token = client.Publish(requestTopic, 0, false, sendCmd)
		token.Wait()
		fmt.Printf("SendCmd: %s\n", strings.Replace(sendCmd, "\r\n", "\\r\\n", -1))
		// 等待回复
		time.Sleep(1 * time.Second) // 等待一段时间来接收回复

		// IN1/DI1联动控制继电器OUT1点动输出5秒：AT+LINKAGE1=3,5,100000,1,1000000\r\n
		sendCmd = "AT+LINKAGE1=3,5,100000,1,1000000\r\n"
		token = client.Publish(requestTopic, 0, false, sendCmd)
		token.Wait()
		fmt.Printf("SendCmd: %s\n", strings.Replace(sendCmd, "\r\n", "\\r\\n", -1))
		// 等待回复
		time.Sleep(1 * time.Second) // 等待一段时间来接收回复

		// 上电默认状态设置为吸合指令：AT+DODEFSTA=1\r\n
		sendCmd = "AT+DODEFSTA=1\r\n"
		token = client.Publish(requestTopic, 0, false, sendCmd)
		token.Wait()
		fmt.Printf("SendCmd: %s\n", strings.Replace(sendCmd, "\r\n", "\\r\\n", -1))
		// 等待回复
		time.Sleep(1 * time.Second) // 等待一段时间来接收回复

		// 使能状态主动上传指令：AT+KPUPLOAD=1\r\n
		sendCmd = "AT+KPUPLOAD=1\r\n"
		token = client.Publish(requestTopic, 0, false, sendCmd)
		token.Wait()
		fmt.Printf("SendCmd: %s\n", strings.Replace(sendCmd, "\r\n", "\\r\\n", -1))
		// 等待回复
		time.Sleep(1 * time.Second) // 等待一段时间来接收回复

		// 使能掉电保存指令：AT+KPKEEP=1\r\n
		sendCmd = "AT+KPKEEP=1\r\n"
		token = client.Publish(requestTopic, 0, false, sendCmd)
		token.Wait()
		fmt.Printf("SendCmd: %s\n", strings.Replace(sendCmd, "\r\n", "\\r\\n", -1))
		// 等待回复
		time.Sleep(1 * time.Second) // 等待一段时间来接收回复
	case 1:
		fmt.Printf("DI开关量输入接口测试：")
		// 读取DI开关量输入接口IN1/DI1的状态指令：AT+OCCH1=?\r\n
		sendCmd := "AT+OCCH1=?\r\n"
		token := client.Publish(requestTopic, 0, false, sendCmd)
		token.Wait()
		fmt.Printf("SendCmd: %s\n", strings.Replace(sendCmd, "\r\n", "\\r\\n", -1))
		// 等待回复
		time.Sleep(1 * time.Second) // 等待一段时间来接收回复

		// 被动上传  AT+OCMOD=0\r\n
		// 定时上传	AT+OCMOD=1,300   1：上传模式  300：上传间隔 单位：10ms
		// 触发上传(所有通道)	AT+OCMOD=2,0
		// 触发上传(单个通道)	AT+OCMOD=3,0
		// 设置DI上传模式：每3秒设置上传一次DI状态：AT+OCMOD=1,300\r\n
		sendCmd = "AT+OCMOD=1,300\r\n"
		token = client.Publish(requestTopic, 0, false, sendCmd)
		token.Wait()
		fmt.Printf("SendCmd: %s\n", strings.Replace(sendCmd, "\r\n", "\\r\\n", -1))
		// 等待回复
		time.Sleep(1 * time.Second) // 等待一段时间来接收回复
	case 2:
		fmt.Printf("AI模拟量输入接口测试：")
		// 设置AI1接口的信号类型是电压型：AT+AIMODE1=0\r\n
		sendCmd := "AT+AIMODE1=0\r\n"
		token := client.Publish(requestTopic, 0, false, sendCmd)
		token.Wait()
		fmt.Printf("SendCmd: %s\n", strings.Replace(sendCmd, "\r\n", "\\r\\n", -1))
		// 等待回复
		time.Sleep(1 * time.Second) // 等待一段时间来接收回复

		// 读取AI1接口实时采样值：AT+AIVALUE1=?\r\n
		sendCmd = "AT+AIVALUE1=?\r\n"
		token = client.Publish(requestTopic, 0, false, sendCmd)
		token.Wait()
		fmt.Printf("SendCmd: %s\n", strings.Replace(sendCmd, "\r\n", "\\r\\n", -1))
		// 等待回复
		time.Sleep(1 * time.Second) // 等待一段时间来接收回复

		// 0：被动上传  使用AT+AIVALUE1=?\r\n指令读取AI1接口实时采样值
		// 1：定时上传	AT+AIUPLOAD1=1,30\r\n   30：上传间隔 单位：100ms
		// 2：触发上传	AT+AIUPLOAD1=2,0,30,0,2000,0,0\r\n  设置 AI1 接口采样值高于 2000 并持续 3 秒触发上传
		// 3：定时+触发上传 AT+AIUPLOAD1=2,30,30,0,2000,0,0\r\n  设置 AI1 接口 3秒上传一次 或 采样值高于 2000 并持续 3 秒触发上传
		// 设置3秒上传1次AI1接口采样值：AT+AIUPLOAD1=1,30\r\n
		sendCmd = "AT+AIUPLOAD1=1,30\r\n"
		token = client.Publish(requestTopic, 0, false, sendCmd)
		token.Wait()
		fmt.Printf("SendCmd: %s\n", strings.Replace(sendCmd, "\r\n", "\\r\\n", -1))
		// 等待回复
		time.Sleep(1 * time.Second) // 等待一段时间来接收回复
	case 3:
		fmt.Printf("VO语音输出接口测试：")
		// 控制VO1接口播放文字“泥人科技”：AT+TTS1=1,0,8\r\n泥人科技
		sendCmd := "AT+TTS1=1,0,8\r\n泥人科技"

		gb2312Str, err := utf8ToGB2312(sendCmd)
		if err != nil {
			fmt.Println("转换失败：", err)
			return
		}

		token := client.Publish(requestTopic, 0, false, gb2312Str)
		token.Wait()
		fmt.Printf("SendCmd: %s\n", strings.Replace(sendCmd, "\r\n", "\\r\\n", -1))
		// 等待回复
		time.Sleep(1 * time.Second) // 等待一段时间来接收回复

		// 控制VO1接口播放语音文件1：AT+AUDIO1=1,10\r\n
		sendCmd = "AT+AUDIO1=1,10\r\n"
		token = client.Publish(requestTopic, 0, false, sendCmd)
		token.Wait()
		fmt.Printf("SendCmd: %s\n", strings.Replace(sendCmd, "\r\n", "\\r\\n", -1))
		// 等待回复
		time.Sleep(1 * time.Second) // 等待一段时间来接收回复

		// 定时播放 VO1接口每天早上8点播放语音文件1：AT+AUTOCONT=2,TASK1,[CYC:1],[T:3,0|1|2|3|4|5|6,08:00:00],[VO:0,1,1,10,1,0],[N:1,0]\r\n
		sendCmd = "AT+AUTOCONT=2,TASK1,[CYC:1],[T:3,0|1|2|3|4|5|6,08:00:00],[VO:0,1,1,10,1,0],[N:1,0]\r\n"
		token = client.Publish(requestTopic, 0, false, sendCmd)
		token.Wait()
		fmt.Printf("SendCmd: %s\n", strings.Replace(sendCmd, "\r\n", "\\r\\n", -1))
		// 等待回复
		time.Sleep(1 * time.Second) // 等待一段时间来接收回复

		// IN1/DI1联动播放语音文件1：AT+AUTOCONT=2,TASK1,[CYC:1],[DI:3,1,1],[VO:0,1,1,10,1,0],[N:1,0]\r\n
		sendCmd = "AT+AUTOCONT=2,TASK1,[CYC:1],[DI:3,1,1],[VO:0,1,1,10,1,0],[N:1,0]\r\n"
		token = client.Publish(requestTopic, 0, false, sendCmd)
		token.Wait()
		fmt.Printf("SendCmd: %s\n", strings.Replace(sendCmd, "\r\n", "\\r\\n", -1))
		// 等待回复
		time.Sleep(1 * time.Second) // 等待一段时间来接收回复

		// 文本播放拓展（发音人、声调、语速、语调）
		// VO1 接口使用
		// 发音人：[m3] 3 晓玲(女声) 51 尹小坚(男声) 52 易小强(男声) 53 田蓓蓓(女声) 54 唐老鸭(效果器) 55 小燕子(女童声)
		// 声调：[i0] 0 - 不识别汉语拼音 1 - 识别汉语拼音
		// 注意： 欢迎[i0]shi3泥人科技  读作：欢迎shi3用泥人科技   欢迎[i1]shi3用泥人科技  读作：欢迎使用泥人科技
		// 1）拼音格式为：1 至 6 位字母 + 1 位数字
		// 2）声调用 1 位数字表示 ：1 阴平、2 阳平、3 上声、4 去声、5 轻声
		// 语速：1-10档 [s5]
		// 语调：1-10档 [t5]
		// 音量：1-10档 [v5]
		// VO1接口使用发音人：晓玲,声调：5,语速：5,语调：5,音量：5播放文本：AT+TTS1=1,0,1,1,39\r\n[m3][s5][t5][v5]欢迎[i0]shi3用泥人科技
		sendCmd = "AT+TTS1=1,0,1,1,39\r\n[m3][s5][t5][v5]欢迎[i0]shi3用泥人科技"
		gb2312Str1, err := utf8ToGB2312(sendCmd)
		if err != nil {
			fmt.Println("转换失败：", err)
			return
		}
		token = client.Publish(requestTopic, 0, false, gb2312Str1)
		token.Wait()
		fmt.Printf("SendCmd: %s\n", strings.Replace(sendCmd, "\r\n", "\\r\\n", -1))
		// 等待回复
		time.Sleep(1 * time.Second) // 等待一段时间来接收回复
	case 4:
		fmt.Printf("电脑开关机功能测试：")
		// 发送电脑开机指令：AT+PCSSSTA=1\r\n
		sendCmd := "AT+PCSSSTA=1\r\n"
		token := client.Publish(requestTopic, 0, false, sendCmd)
		token.Wait()
		fmt.Printf("SendCmd: %s\n", strings.Replace(sendCmd, "\r\n", "\\r\\n", -1))
		// 等待回复
		time.Sleep(1 * time.Second) // 等待一段时间来接收回复

		// 每天早上8点开机： AT+AUTOCONT=2,TaskName1,[T:3,0|1|2|3|4|5|6,08:00:00],[PC:0,1],[N:1,0]\r\n
		sendCmd = "AT+AUTOCONT=2,TaskName1,[T:3,0|1|2|3|4|5|6,08:00:00],[PC:0,1],[N:1,0]\r\n"
		token = client.Publish(requestTopic, 0, false, sendCmd)
		token.Wait()
		fmt.Printf("SendCmd: %s\n", strings.Replace(sendCmd, "\r\n", "\\r\\n", -1))
		// 等待回复
		time.Sleep(1 * time.Second) // 等待一段时间来接收回复

		// 0：被动上传  使用AT+PCSSSTA=?\r\n指令读取开关机状态
		// 1：定时上传	AT+PCSSUPLOAD=1,30\r\n   30：上传间隔 单位：100ms
		// 2：触发上传	AT+PCSSUPLOAD=2\r\n
		// 3：定时+触发上传 AT+PCSSUPLOAD=3,30\r\n

		// 设置3秒上传1次电脑开关机状态：AT+PCSSUPLOAD=1,30\r\n
		sendCmd = "AT+PCSSUPLOAD=1,30\r\n"
		token = client.Publish(requestTopic, 0, false, sendCmd)
		token.Wait()
		fmt.Printf("SendCmd: %s\n", strings.Replace(sendCmd, "\r\n", "\\r\\n", -1))
		// 等待回复
		time.Sleep(1 * time.Second) // 等待一段时间来接收回复

		// 上电自动开机功能启用：AT+PCSSAUTO=1\r\n
		sendCmd = "AT+PCSSAUTO=1\r\n"
		token = client.Publish(requestTopic, 0, false, sendCmd)
		token.Wait()
		fmt.Printf("SendCmd: %s\n", strings.Replace(sendCmd, "\r\n", "\\r\\n", -1))
		// 等待回复
		time.Sleep(1 * time.Second) // 等待一段时间来接收回复

		// 上电禁用机箱按键，即按键失效：AT+PCSSEXTKEY=1\r\n
		sendCmd = "AT+PCSSEXTKEY=1\r\n"
		token = client.Publish(requestTopic, 0, false, sendCmd)
		token.Wait()
		fmt.Printf("SendCmd: %s\n", strings.Replace(sendCmd, "\r\n", "\\r\\n", -1))
		// 等待回复
		time.Sleep(1 * time.Second) // 等待一段时间来接收回复
	default:
		fmt.Printf("输入的ExecType值不对，值范围0~4")
	}

	fmt.Println("测试完成！")

	fmt.Println("更多控制指令的详细解释请查阅《网络控制器AT指令手册V2.9.PDF》")
	fmt.Println("本Demo仅用于开发参考，不能直接用于商业项目实施！")
}
