mirror of
https://github.com/silenceper/wechat.git
synced 2026-02-13 17:22:26 +08:00
116
device/authorize.go
Normal file
116
device/authorize.go
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
package device
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/silenceper/wechat/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DeviceAdd 添加设备标识
|
||||||
|
DeviceAdd = iota
|
||||||
|
// DeviceUpgrade 更新设备标识
|
||||||
|
DeviceUpgrade
|
||||||
|
)
|
||||||
|
|
||||||
|
type reqDeviceAuthorize struct {
|
||||||
|
// 设备id的个数
|
||||||
|
DeviceNum string `json:"device_num"`
|
||||||
|
// 设备id的列表,json的array格式,其size必须等于device_num
|
||||||
|
DeviceList []ReqDevice `json:"device_list"`
|
||||||
|
// 请求操作的类型,限定取值为:0:设备授权(缺省值为0) 1:设备更新(更新已授权设备的各属性值)
|
||||||
|
OpType string `json:"op_type,omitempty"`
|
||||||
|
// 设备的产品编号(由微信硬件平台分配)。可在公众号设备功能管理页面查询。
|
||||||
|
//当 op_type 为‘0’,product_id 为‘1’时,不要填写 product_id 字段(会引起不必要错误);
|
||||||
|
//当 op_typy 为‘0’,product_id 不为‘1’时,必须填写 product_id 字段;
|
||||||
|
//当 op_type 为 1 时,不要填写 product_id 字段。
|
||||||
|
ProductID string `json:"product_id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//ReqDevice 设备授权实体
|
||||||
|
type ReqDevice struct {
|
||||||
|
// 设备的 device id
|
||||||
|
ID string `json:"id"`
|
||||||
|
// 设备的mac地址 格式采用16进制串的方式(长度为12字节),
|
||||||
|
// 不需要0X前缀,如: 1234567890AB
|
||||||
|
Mac string `json:"mac"`
|
||||||
|
// 支持以下四种连接协议:
|
||||||
|
// android classic bluetooth – 1
|
||||||
|
// ios classic bluetooth – 2
|
||||||
|
// ble – 3
|
||||||
|
// wifi -- 4
|
||||||
|
// 一个设备可以支持多种连接类型,用符号"|"做分割,客户端优先选择靠前的连接方式(优先级按|关系的排序依次降低),举例:
|
||||||
|
// 1:表示设备仅支持andiod classic bluetooth 1|2:表示设备支持andiod 和ios 两种classic bluetooth,但是客户端优先选择andriod classic bluetooth 协议,如果andriod classic bluetooth协议连接失败,再选择ios classic bluetooth协议进行连接
|
||||||
|
// (注:安卓平台不同时支持BLE和classic类型)
|
||||||
|
ConnectProtocol string `json:"connect_protocol"`
|
||||||
|
//auth及通信的加密key,第三方需要将key烧制在设备上(128bit),格式采用16进制串的方式(长度为32字节),不需要0X前缀,如: 1234567890ABCDEF1234567890ABCDEF
|
||||||
|
AuthKey string `json:"auth_key"`
|
||||||
|
// 断开策略,目前支持: 1:退出公众号页面时即断开连接 2:退出公众号之后保持连接不断开
|
||||||
|
CloseStrategy string `json:"close_strategy"`
|
||||||
|
//连接策略,32位整型,按bit位置位,目前仅第1bit和第3bit位有效(bit置0为无效,1为有效;第2bit已被废弃),且bit位可以按或置位(如1|4=5),各bit置位含义说明如下:
|
||||||
|
//1:(第1bit置位)在公众号对话页面,不停的尝试连接设备
|
||||||
|
//4:(第3bit置位)处于非公众号页面(如主界面等),微信自动连接。当用户切换微信到前台时,可能尝试去连接设备,连上后一定时间会断开
|
||||||
|
ConnStrategy string `json:"conn_strategy"`
|
||||||
|
// auth version,设备和微信进行auth时,会根据该版本号来确认auth buf和auth key的格式(各version对应的auth buf及key的具体格式可以参看“客户端蓝牙外设协议”),该字段目前支持取值:
|
||||||
|
// 0:不加密的version
|
||||||
|
// 1:version 1
|
||||||
|
AuthVer string `json:"auth_ver"`
|
||||||
|
// 表示mac地址在厂商广播manufature data里含有mac地址的偏移,取值如下:
|
||||||
|
// -1:在尾部、
|
||||||
|
// -2:表示不包含mac地址 其他:非法偏移
|
||||||
|
ManuMacPos string `json:"manu_mac_pos"`
|
||||||
|
// 表示mac地址在厂商serial number里含有mac地址的偏移,取值如下:
|
||||||
|
// -1:表示在尾部
|
||||||
|
// -2:表示不包含mac地址 其他:非法偏移
|
||||||
|
SerMacPost string `json:"ser_mac_post"`
|
||||||
|
// 精简协议类型,取值如下:计步设备精简协议:1 (若该字段填1,connect_protocol 必须包括3。非精简协议设备切勿填写该字段)
|
||||||
|
BleSimpleProtocol string `json:"ble_simple_protocol,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//ResBaseInfo 授权回调实体
|
||||||
|
type ResBaseInfo struct {
|
||||||
|
BaseInfo struct {
|
||||||
|
DeviceType string `json:"device_type"`
|
||||||
|
DeviceID string `json:"device_id"`
|
||||||
|
} `json:"base_info"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 授权回调根信息
|
||||||
|
type resDeviceAuthorize struct {
|
||||||
|
util.CommonError
|
||||||
|
Resp []ResBaseInfo `json:"resp"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeviceAuthorize 设备授权
|
||||||
|
func (d *Device) DeviceAuthorize(devices []ReqDevice, opType int, product string) (res []ResBaseInfo, err error) {
|
||||||
|
var accessToken string
|
||||||
|
accessToken, err = d.GetAccessToken()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
uri := fmt.Sprintf("%s?access_token=%s", uriAuthorize, accessToken)
|
||||||
|
req := reqDeviceAuthorize{
|
||||||
|
DeviceNum: fmt.Sprintf("%d", len(devices)),
|
||||||
|
DeviceList: devices,
|
||||||
|
OpType: fmt.Sprintf("%d", opType),
|
||||||
|
ProductID: product,
|
||||||
|
}
|
||||||
|
var response []byte
|
||||||
|
response, err = util.PostJSON(uri, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var result resDeviceAuthorize
|
||||||
|
err = json.Unmarshal(response, &result)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if result.ErrCode != 0 {
|
||||||
|
err = fmt.Errorf("DeviceAuthorize Error , errcode=%d , errmsg=%s", result.ErrCode, result.ErrMsg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res = result.Resp
|
||||||
|
return
|
||||||
|
}
|
||||||
106
device/bind.go
Normal file
106
device/bind.go
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
package device
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/silenceper/wechat/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ReqBind 设备绑定解绑共通实体
|
||||||
|
type ReqBind struct {
|
||||||
|
Ticket string `json:"ticket,omitempty"`
|
||||||
|
DeviceID string `json:"device_id"`
|
||||||
|
OpenID string `json:"openid"`
|
||||||
|
}
|
||||||
|
type resBind struct {
|
||||||
|
BaseResp util.CommonError `json:"base_resp"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind 设备绑定
|
||||||
|
func (d *Device) Bind(req ReqBind) (err error) {
|
||||||
|
var accessToken string
|
||||||
|
if accessToken, err = d.GetAccessToken(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
uri := fmt.Sprintf("%s?access_token=%s", uriBind, accessToken)
|
||||||
|
var response []byte
|
||||||
|
if response, err = util.PostJSON(uri, req); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var result resBind
|
||||||
|
if err = json.Unmarshal(response, &result); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if result.BaseResp.ErrCode != 0 {
|
||||||
|
err = fmt.Errorf("DeviceBind Error , errcode=%d , errmsg=%s", result.BaseResp.ErrCode, result.BaseResp.ErrMsg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unbind 设备解绑
|
||||||
|
func (d *Device) Unbind(req ReqBind) (err error) {
|
||||||
|
var accessToken string
|
||||||
|
if accessToken, err = d.GetAccessToken(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
uri := fmt.Sprintf("%s?access_token=%s", uriUnbind, accessToken)
|
||||||
|
var response []byte
|
||||||
|
if response, err = util.PostJSON(uri, req); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var result resBind
|
||||||
|
if err = json.Unmarshal(response, &result); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if result.BaseResp.ErrCode != 0 {
|
||||||
|
err = fmt.Errorf("DeviceBind Error , errcode=%d , errmsg=%s", result.BaseResp.ErrCode, result.BaseResp.ErrMsg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// CompelBind 强制绑定用户和设备
|
||||||
|
func (d *Device) CompelBind(req ReqBind) (err error) {
|
||||||
|
var accessToken string
|
||||||
|
if accessToken, err = d.GetAccessToken(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
uri := fmt.Sprintf("%s?access_token=%s", uriCompelBind, accessToken)
|
||||||
|
var response []byte
|
||||||
|
if response, err = util.PostJSON(uri, req); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var result resBind
|
||||||
|
if err = json.Unmarshal(response, &result); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if result.BaseResp.ErrCode != 0 {
|
||||||
|
err = fmt.Errorf("DeviceBind Error , errcode=%d , errmsg=%s", result.BaseResp.ErrCode, result.BaseResp.ErrMsg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// CompelUnbind 强制解绑用户和设备
|
||||||
|
func (d *Device) CompelUnbind(req ReqBind) (err error) {
|
||||||
|
var accessToken string
|
||||||
|
if accessToken, err = d.GetAccessToken(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
uri := fmt.Sprintf("%s?access_token=%s", uriCompelUnbind, accessToken)
|
||||||
|
var response []byte
|
||||||
|
if response, err = util.PostJSON(uri, req); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var result resBind
|
||||||
|
if err = json.Unmarshal(response, &result); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if result.BaseResp.ErrCode != 0 {
|
||||||
|
err = fmt.Errorf("DeviceBind Error , errcode=%d , errmsg=%s", result.BaseResp.ErrCode, result.BaseResp.ErrMsg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
60
device/device.go
Normal file
60
device/device.go
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
package device
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/silenceper/wechat/context"
|
||||||
|
"github.com/silenceper/wechat/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
uriAuthorize = "https://api.weixin.qq.com/device/authorize_device"
|
||||||
|
uriQRCode = "https://api.weixin.qq.com/device/create_qrcode"
|
||||||
|
uriVerifyQRCode = "https://api.weixin.qq.com/device/verify_qrcode"
|
||||||
|
uriBind = "https://api.weixin.qq.com/device/bind"
|
||||||
|
uriUnbind = "https://api.weixin.qq.com/device/unbind"
|
||||||
|
uriCompelBind = "https://api.weixin.qq.com/device/compel_bind"
|
||||||
|
uriCompelUnbind = "https://api.weixin.qq.com/device/compel_unbind"
|
||||||
|
uriState = "https://api.weixin.qq.com/device/get_stat"
|
||||||
|
)
|
||||||
|
|
||||||
|
//Device struct
|
||||||
|
type Device struct {
|
||||||
|
*context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
//NewDevice 实例
|
||||||
|
func NewDevice(context *context.Context) *Device {
|
||||||
|
device := new(Device)
|
||||||
|
device.Context = context
|
||||||
|
return device
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResDeviceState 设备状态响应实体
|
||||||
|
type ResDeviceState struct {
|
||||||
|
util.CommonError
|
||||||
|
Status int `json:"status"`
|
||||||
|
StatusInfo string `json:"status_info"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// State 设备状态查询
|
||||||
|
func (d *Device) State(device string) (res ResDeviceState, err error) {
|
||||||
|
var accessToken string
|
||||||
|
if accessToken, err = d.GetAccessToken(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
uri := fmt.Sprintf("%s?access_token=%s&device_id=%s", uriState, accessToken, device)
|
||||||
|
var response []byte
|
||||||
|
if response, err = util.HTTPGet(uri); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = json.Unmarshal(response, &res); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if res.ErrCode != 0 {
|
||||||
|
err = fmt.Errorf("DeviceState Error , errcode=%d , errmsg=%s", res.ErrCode, res.ErrMsg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
9
device/message.go
Normal file
9
device/message.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package device
|
||||||
|
|
||||||
|
//MsgDevice 设备消息响应
|
||||||
|
type MsgDevice struct {
|
||||||
|
DeviceType string
|
||||||
|
DeviceID string
|
||||||
|
SessionID string
|
||||||
|
OpenID string
|
||||||
|
}
|
||||||
76
device/qrcode.go
Normal file
76
device/qrcode.go
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
package device
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/silenceper/wechat/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
//ResCreateQRCode 获取二维码的返回实体
|
||||||
|
type ResCreateQRCode struct {
|
||||||
|
util.CommonError
|
||||||
|
DeviceNum int `json:"device_num"`
|
||||||
|
CodeList []struct {
|
||||||
|
DeviceID string `json:"device_id"`
|
||||||
|
Ticket string `json:"ticket"`
|
||||||
|
} `json:"code_list"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateQRCode 获取设备二维码
|
||||||
|
func (d *Device) CreateQRCode(devices []string) (res ResCreateQRCode, err error) {
|
||||||
|
var accessToken string
|
||||||
|
if accessToken, err = d.GetAccessToken(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
uri := fmt.Sprintf("%s?access_token=%s", uriQRCode, accessToken)
|
||||||
|
req := map[string]interface{}{
|
||||||
|
"device_num": len(devices),
|
||||||
|
"device_id_list": devices,
|
||||||
|
}
|
||||||
|
var response []byte
|
||||||
|
if response, err = util.PostJSON(uri, req); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = json.Unmarshal(response, &res); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if res.ErrCode != 0 {
|
||||||
|
err = fmt.Errorf("DeviceCreateQRCode Error , errcode=%d , errmsg=%s", res.ErrCode, res.ErrMsg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//ResVerifyQRCode 验证授权结果实体
|
||||||
|
type ResVerifyQRCode struct {
|
||||||
|
util.CommonError
|
||||||
|
DeviceType string `json:"device_type"`
|
||||||
|
DeviceID string `json:"device_id"`
|
||||||
|
Mac string `json:"mac"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyQRCode 验证设备二维码
|
||||||
|
func (d *Device) VerifyQRCode(ticket string) (res ResVerifyQRCode, err error) {
|
||||||
|
var accessToken string
|
||||||
|
if accessToken, err = d.GetAccessToken(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
uri := fmt.Sprintf("%s?access_token=%s", uriVerifyQRCode, accessToken)
|
||||||
|
req := map[string]interface{}{
|
||||||
|
"ticket": ticket,
|
||||||
|
}
|
||||||
|
fmt.Println(req)
|
||||||
|
var response []byte
|
||||||
|
if response, err = util.PostJSON(uri, req); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = json.Unmarshal(response, &res); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if res.ErrCode != 0 {
|
||||||
|
err = fmt.Errorf("DeviceCreateQRCode Error , errcode=%d , errmsg=%s", res.ErrCode, res.ErrMsg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
package message
|
package message
|
||||||
|
|
||||||
import "encoding/xml"
|
import (
|
||||||
|
"encoding/xml"
|
||||||
|
"github.com/silenceper/wechat/device"
|
||||||
|
)
|
||||||
|
|
||||||
// MsgType 基本消息类型
|
// MsgType 基本消息类型
|
||||||
type MsgType string
|
type MsgType string
|
||||||
@@ -148,10 +151,13 @@ type MixMessage struct {
|
|||||||
UnionID string `xml:"UnionId"`
|
UnionID string `xml:"UnionId"`
|
||||||
|
|
||||||
// 内容审核相关
|
// 内容审核相关
|
||||||
IsRisky bool `xml:"isrisky"`
|
IsRisky bool `xml:"isrisky"`
|
||||||
ExtraInfoJSON string `xml:"extra_info_json"`
|
ExtraInfoJSON string `xml:"extra_info_json"`
|
||||||
TraceID string `xml:"trace_id"`
|
TraceID string `xml:"trace_id"`
|
||||||
StatusCode int `xml:"status_code"`
|
StatusCode int `xml:"status_code"`
|
||||||
|
|
||||||
|
//设备相关
|
||||||
|
device.MsgDevice
|
||||||
}
|
}
|
||||||
|
|
||||||
//EventPic 发图事件推送
|
//EventPic 发图事件推送
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package wechat
|
package wechat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/silenceper/wechat/device"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@@ -111,3 +112,8 @@ func (wc *Wechat) GetQR() *qr.QR {
|
|||||||
func (wc *Wechat) GetMiniProgram() *miniprogram.MiniProgram {
|
func (wc *Wechat) GetMiniProgram() *miniprogram.MiniProgram {
|
||||||
return miniprogram.NewMiniProgram(wc.Context)
|
return miniprogram.NewMiniProgram(wc.Context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetDevice 获取智能设备的实例
|
||||||
|
func (wc *Wechat) GetDevice() *device.Device {
|
||||||
|
return device.NewDevice(wc.Context)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user