diff --git a/main.go b/main.go index 3bbf632f..e2698331 100644 --- a/main.go +++ b/main.go @@ -89,7 +89,7 @@ func main() { roborock.Init() // roborock source homekit.Init() // homekit source ring.Init() // ring source - tuya.Init() // tuya source + tuya.Init() // tuya source nest.Init() // nest source bubble.Init() // bubble source expr.Init() // expr source diff --git a/pkg/hap/camera/accessory.go b/pkg/hap/camera/accessory.go index 42037d96..886b035d 100644 --- a/pkg/hap/camera/accessory.go +++ b/pkg/hap/camera/accessory.go @@ -62,7 +62,7 @@ func ServiceCameraRTPStreamManagement() *hap.Service { VideoAttrs: []VideoAttrs{ {Width: 1920, Height: 1080, Framerate: 30}, {Width: 1280, Height: 720, Framerate: 30}, // important for iPhones - {Width: 320, Height: 240, Framerate: 15}, // apple watch + {Width: 320, Height: 240, Framerate: 15}, // apple watch }, }, }, diff --git a/pkg/tapo/client.go b/pkg/tapo/client.go index c19267ff..5a9af501 100644 --- a/pkg/tapo/client.go +++ b/pkg/tapo/client.go @@ -292,7 +292,7 @@ func dial(req *http.Request, brand, username, password string) (net.Conn, *http. return nil, nil, err } _, _ = io.Copy(io.Discard, res.Body) // discard leftovers - _ = res.Body.Close() // ignore response body + _ = res.Body.Close() // ignore response body auth := res.Header.Get("WWW-Authenticate") diff --git a/pkg/tuya/api.go b/pkg/tuya/api.go index 4ee0bf8f..29152951 100644 --- a/pkg/tuya/api.go +++ b/pkg/tuya/api.go @@ -17,146 +17,146 @@ import ( ) type TuyaClient struct { - httpClient *http.Client - mqtt *TuyaMQTT - apiURL string - rtspURL string - hlsURL string - sessionId string - clientId string - clientSecret string - deviceId string - accessToken string - refreshToken string - expireTime int64 - uid string - motoId string - auth string - skill *Skill - iceServers []pionWebrtc.ICEServer - medias []*core.Media - hasBackchannel bool + httpClient *http.Client + mqtt *TuyaMQTT + apiURL string + rtspURL string + hlsURL string + sessionId string + clientId string + clientSecret string + deviceId string + accessToken string + refreshToken string + expireTime int64 + uid string + motoId string + auth string + skill *Skill + iceServers []pionWebrtc.ICEServer + medias []*core.Media + hasBackchannel bool } type Token struct { - UID string `json:"uid"` - AccessToken string `json:"access_token"` - RefreshToken string `json:"refresh_token"` - ExpireTime int64 `json:"expire_time"` + UID string `json:"uid"` + AccessToken string `json:"access_token"` + RefreshToken string `json:"refresh_token"` + ExpireTime int64 `json:"expire_time"` } type AudioAttributes struct { - CallMode []int `json:"call_mode"` // 1 = one way, 2 = two way - HardwareCapability []int `json:"hardware_capability"` // 1 = mic, 2 = speaker + CallMode []int `json:"call_mode"` // 1 = one way, 2 = two way + HardwareCapability []int `json:"hardware_capability"` // 1 = mic, 2 = speaker } type OpenApiICE struct { - Urls string `json:"urls"` - Username string `json:"username"` - Credential string `json:"credential"` - TTL int `json:"ttl"` + Urls string `json:"urls"` + Username string `json:"username"` + Credential string `json:"credential"` + TTL int `json:"ttl"` } type WebICE struct { - Urls string `json:"urls"` - Username string `json:"username,omitempty"` - Credential string `json:"credential,omitempty"` + Urls string `json:"urls"` + Username string `json:"username,omitempty"` + Credential string `json:"credential,omitempty"` } type P2PConfig struct { - Ices []OpenApiICE `json:"ices"` + Ices []OpenApiICE `json:"ices"` } type Skill struct { - WebRTC int `json:"webrtc"` + WebRTC int `json:"webrtc"` Audios []struct { - Channels int `json:"channels"` - DataBit int `json:"dataBit"` - CodecType int `json:"codecType"` - SampleRate int `json:"sampleRate"` + Channels int `json:"channels"` + DataBit int `json:"dataBit"` + CodecType int `json:"codecType"` + SampleRate int `json:"sampleRate"` } `json:"audios"` Videos []struct { - StreamType int `json:"streamType"` // streamType = 2 => main stream - streamType = 4 => sub stream - ProfileId string `json:"profileId"` - Width int `json:"width"` - CodecType int `json:"codecType"` - SampleRate int `json:"sampleRate"` - Height int `json:"height"` + StreamType int `json:"streamType"` // streamType = 2 => main stream - streamType = 4 => sub stream + ProfileId string `json:"profileId"` + Width int `json:"width"` + CodecType int `json:"codecType"` + SampleRate int `json:"sampleRate"` + Height int `json:"height"` } `json:"videos"` } type WebRTConfig struct { - AudioAttributes AudioAttributes `json:"audio_attributes"` - Auth string `json:"auth"` - ID string `json:"id"` - MotoID string `json:"moto_id"` - P2PConfig P2PConfig `json:"p2p_config"` - ProtocolVersion string `json:"protocol_version"` - Skill string `json:"skill"` - SupportsWebRTCRecord bool `json:"supports_webrtc_record"` - SupportsWebRTC bool `json:"supports_webrtc"` - VedioClaritiy int `json:"vedio_clarity"` - VideoClaritiy int `json:"video_clarity"` - VideoClarities []int `json:"video_clarities"` + AudioAttributes AudioAttributes `json:"audio_attributes"` + Auth string `json:"auth"` + ID string `json:"id"` + MotoID string `json:"moto_id"` + P2PConfig P2PConfig `json:"p2p_config"` + ProtocolVersion string `json:"protocol_version"` + Skill string `json:"skill"` + SupportsWebRTCRecord bool `json:"supports_webrtc_record"` + SupportsWebRTC bool `json:"supports_webrtc"` + VedioClaritiy int `json:"vedio_clarity"` + VideoClaritiy int `json:"video_clarity"` + VideoClarities []int `json:"video_clarities"` } type OpenIoTHubConfig struct { - Url string `json:"url"` - ClientID string `json:"client_id"` - Username string `json:"username"` - Password string `json:"password"` + Url string `json:"url"` + ClientID string `json:"client_id"` + Username string `json:"username"` + Password string `json:"password"` SinkTopic struct { IPC string `json:"ipc"` } `json:"sink_topic"` SourceSink struct { IPC string `json:"ipc"` } `json:"source_topic"` - ExpireTime int `json:"expire_time"` + ExpireTime int `json:"expire_time"` } type WebRTCConfigResponse struct { - Success bool `json:"success"` - Result WebRTConfig `json:"result"` - Msg string `json:"msg,omitempty"` - Code int `json:"code,omitempty"` + Success bool `json:"success"` + Result WebRTConfig `json:"result"` + Msg string `json:"msg,omitempty"` + Code int `json:"code,omitempty"` } type TokenResponse struct { - Success bool `json:"success"` - Result Token `json:"result"` - Msg string `json:"msg,omitempty"` - Code int `json:"code,omitempty"` + Success bool `json:"success"` + Result Token `json:"result"` + Msg string `json:"msg,omitempty"` + Code int `json:"code,omitempty"` } type AllocateRequest struct { - Type string `json:"type"` + Type string `json:"type"` } type AllocateResponse struct { - Success bool `json:"success"` + Success bool `json:"success"` Result struct { URL string `json:"url"` } `json:"result"` - Msg string `json:"msg,omitempty"` - Code int `json:"code,omitempty"` + Msg string `json:"msg,omitempty"` + Code int `json:"code,omitempty"` } type OpenIoTHubConfigRequest struct { - UID string `json:"uid"` - UniqueID string `json:"unique_id"` - LinkType string `json:"link_type"` - Topics string `json:"topics"` + UID string `json:"uid"` + UniqueID string `json:"unique_id"` + LinkType string `json:"link_type"` + Topics string `json:"topics"` } type OpenIoTHubConfigResponse struct { - Success bool `json:"success"` - Result OpenIoTHubConfig `json:"result"` - Msg string `json:"msg,omitempty"` - Code int `json:"code,omitempty"` + Success bool `json:"success"` + Result OpenIoTHubConfig `json:"result"` + Msg string `json:"msg,omitempty"` + Code int `json:"code,omitempty"` } const ( - defaultTimeout = 5 * time.Second + defaultTimeout = 5 * time.Second ) func NewTuyaClient(openAPIURL string, deviceId string, uid string, clientId string, clientSecret string, streamMode string) (*TuyaClient, error) { @@ -164,7 +164,7 @@ func NewTuyaClient(openAPIURL string, deviceId string, uid string, clientId stri httpClient: &http.Client{Timeout: defaultTimeout}, mqtt: &TuyaMQTT{waiter: core.Waiter{}}, apiURL: openAPIURL, - sessionId: core.RandString(6, 62), + sessionId: core.RandString(6, 62), clientId: clientId, deviceId: deviceId, clientSecret: clientSecret, @@ -202,7 +202,7 @@ func (c *TuyaClient) Close() { c.httpClient.CloseIdleConnections() } -func(c *TuyaClient) Request(method string, url string, body any) ([]byte, error) { +func (c *TuyaClient) Request(method string, url string, body any) ([]byte, error) { var bodyReader io.Reader if body != nil { jsonBody, err := json.Marshal(body) @@ -249,7 +249,7 @@ func(c *TuyaClient) Request(method string, url string, body any) ([]byte, error) return res, nil } -func(c *TuyaClient) InitToken() (err error) { +func (c *TuyaClient) InitToken() (err error) { url := fmt.Sprintf("https://%s/v1.0/token?grant_type=1", c.apiURL) c.accessToken = "" @@ -259,7 +259,7 @@ func(c *TuyaClient) InitToken() (err error) { if err != nil { return err } - + var tokenResponse TokenResponse err = json.Unmarshal(body, &tokenResponse) if err != nil { @@ -277,139 +277,139 @@ func(c *TuyaClient) InitToken() (err error) { return nil } -func(c *TuyaClient) InitDevice() (err error) { - url := fmt.Sprintf("https://%s/v1.0/users/%s/devices/%s/webrtc-configs", c.apiURL, c.uid, c.deviceId) +func (c *TuyaClient) InitDevice() (err error) { + url := fmt.Sprintf("https://%s/v1.0/users/%s/devices/%s/webrtc-configs", c.apiURL, c.uid, c.deviceId) - body, err := c.Request("GET", url, nil) - if err != nil { - return err - } + body, err := c.Request("GET", url, nil) + if err != nil { + return err + } - var webRTCConfigResponse WebRTCConfigResponse - err = json.Unmarshal(body, &webRTCConfigResponse) - if err != nil { - return err - } + var webRTCConfigResponse WebRTCConfigResponse + err = json.Unmarshal(body, &webRTCConfigResponse) + if err != nil { + return err + } if !webRTCConfigResponse.Success { return fmt.Errorf("error: %s", webRTCConfigResponse.Msg) } c.motoId = webRTCConfigResponse.Result.MotoID - c.auth = webRTCConfigResponse.Result.Auth + c.auth = webRTCConfigResponse.Result.Auth - c.skill = &Skill{ - Audios: []struct { - Channels int `json:"channels"` - DataBit int `json:"dataBit"` - CodecType int `json:"codecType"` - SampleRate int `json:"sampleRate"` - }{}, - Videos: []struct { - StreamType int `json:"streamType"` - ProfileId string `json:"profileId"` - Width int `json:"width"` - CodecType int `json:"codecType"` - SampleRate int `json:"sampleRate"` - Height int `json:"height"` - }{}, - } + c.skill = &Skill{ + Audios: []struct { + Channels int `json:"channels"` + DataBit int `json:"dataBit"` + CodecType int `json:"codecType"` + SampleRate int `json:"sampleRate"` + }{}, + Videos: []struct { + StreamType int `json:"streamType"` + ProfileId string `json:"profileId"` + Width int `json:"width"` + CodecType int `json:"codecType"` + SampleRate int `json:"sampleRate"` + Height int `json:"height"` + }{}, + } - if webRTCConfigResponse.Result.Skill != "" { - _ = json.Unmarshal([]byte(webRTCConfigResponse.Result.Skill), c.skill) - } + if webRTCConfigResponse.Result.Skill != "" { + _ = json.Unmarshal([]byte(webRTCConfigResponse.Result.Skill), c.skill) + } - var audioDirection string - if contains(webRTCConfigResponse.Result.AudioAttributes.CallMode, 2) && - contains(webRTCConfigResponse.Result.AudioAttributes.HardwareCapability, 1) { - audioDirection = core.DirectionSendRecv + var audioDirection string + if contains(webRTCConfigResponse.Result.AudioAttributes.CallMode, 2) && + contains(webRTCConfigResponse.Result.AudioAttributes.HardwareCapability, 1) { + audioDirection = core.DirectionSendRecv c.hasBackchannel = true - } else { - audioDirection = core.DirectionRecvonly + } else { + audioDirection = core.DirectionRecvonly c.hasBackchannel = false - } - - c.medias = make([]*core.Media, 0) - - if len(c.skill.Audios) > 0 { - // Use the first Audio-Codec - audio := c.skill.Audios[0] + } - c.medias = append(c.medias, &core.Media{ - Kind: core.KindAudio, - Direction: audioDirection, - Codecs: []*core.Codec{ - { - Name: "PCMU", - ClockRate: uint32(audio.SampleRate), - Channels: uint8(audio.Channels), - }, - }, - }) - } else { - // Use default values for Audio - c.medias = append(c.medias, &core.Media{ - Kind: core.KindAudio, - Direction: core.DirectionRecvonly, - Codecs: []*core.Codec{ - { - Name: "PCMU", - ClockRate: uint32(8000), - Channels: uint8(1), - }, - }, - }) - } + c.medias = make([]*core.Media, 0) - if len(c.skill.Videos) > 0 { - // Use the first Video-Codec - video := c.skill.Videos[0] + if len(c.skill.Audios) > 0 { + // Use the first Audio-Codec + audio := c.skill.Audios[0] - c.medias = append(c.medias, &core.Media{ - Kind: core.KindVideo, - Direction: core.DirectionRecvonly, - Codecs: []*core.Codec{ - { - Name: core.CodecH265, - ClockRate: uint32(video.SampleRate), - PayloadType: 96, - }, + c.medias = append(c.medias, &core.Media{ + Kind: core.KindAudio, + Direction: audioDirection, + Codecs: []*core.Codec{ { - Name: core.CodecH264, - ClockRate: uint32(video.SampleRate), - PayloadType: 96, - }, - }, - }) - } else { - // Use default values for Video - c.medias = append(c.medias, &core.Media{ - Kind: core.KindVideo, - Direction: core.DirectionRecvonly, - Codecs: []*core.Codec{ - { - Name: core.CodecH264, - ClockRate: uint32(90000), - PayloadType: 96, - }, - }, - }) - } + Name: "PCMU", + ClockRate: uint32(audio.SampleRate), + Channels: uint8(audio.Channels), + }, + }, + }) + } else { + // Use default values for Audio + c.medias = append(c.medias, &core.Media{ + Kind: core.KindAudio, + Direction: core.DirectionRecvonly, + Codecs: []*core.Codec{ + { + Name: "PCMU", + ClockRate: uint32(8000), + Channels: uint8(1), + }, + }, + }) + } - iceServersBytes, err := json.Marshal(&webRTCConfigResponse.Result.P2PConfig.Ices) - if err != nil { - return err - } + if len(c.skill.Videos) > 0 { + // Use the first Video-Codec + video := c.skill.Videos[0] - c.iceServers, err = webrtc.UnmarshalICEServers([]byte(iceServersBytes)) - if err != nil { - return err - } + c.medias = append(c.medias, &core.Media{ + Kind: core.KindVideo, + Direction: core.DirectionRecvonly, + Codecs: []*core.Codec{ + { + Name: core.CodecH265, + ClockRate: uint32(video.SampleRate), + PayloadType: 96, + }, + { + Name: core.CodecH264, + ClockRate: uint32(video.SampleRate), + PayloadType: 96, + }, + }, + }) + } else { + // Use default values for Video + c.medias = append(c.medias, &core.Media{ + Kind: core.KindVideo, + Direction: core.DirectionRecvonly, + Codecs: []*core.Codec{ + { + Name: core.CodecH264, + ClockRate: uint32(90000), + PayloadType: 96, + }, + }, + }) + } - return nil + iceServersBytes, err := json.Marshal(&webRTCConfigResponse.Result.P2PConfig.Ices) + if err != nil { + return err + } + + c.iceServers, err = webrtc.UnmarshalICEServers([]byte(iceServersBytes)) + if err != nil { + return err + } + + return nil } -func(c *TuyaClient) GetStreamUrl(streamType string) (err error) { +func (c *TuyaClient) GetStreamUrl(streamType string) (err error) { url := fmt.Sprintf("https://%s/v1.0/devices/%s/stream/actions/allocate", c.apiURL, c.deviceId) request := &AllocateRequest{ @@ -443,7 +443,7 @@ func(c *TuyaClient) GetStreamUrl(streamType string) (err error) { return nil } -func(c *TuyaClient) LoadHubConfig() (config *OpenIoTHubConfig, err error) { +func (c *TuyaClient) LoadHubConfig() (config *OpenIoTHubConfig, err error) { url := fmt.Sprintf("https://%s/v2.0/open-iot-hub/access/config", c.apiURL) request := &OpenIoTHubConfigRequest{ @@ -467,53 +467,53 @@ func(c *TuyaClient) LoadHubConfig() (config *OpenIoTHubConfig, err error) { if !openIoTHubConfigResponse.Success { return nil, fmt.Errorf("error: %s", openIoTHubConfigResponse.Msg) } - + return &openIoTHubConfigResponse.Result, nil } // Search the streamType based on the selection "main" or "sub" func (c *TuyaClient) getStreamType(streamChoice string) uint32 { // Default streamType if nothing is found - defaultStreamType := uint32(1) + defaultStreamType := uint32(1) + + if c.skill == nil || len(c.skill.Videos) == 0 { + return defaultStreamType + } - if c.skill == nil || len(c.skill.Videos) == 0 { - return defaultStreamType - } - // Find the highest and lowest resolution - var highestResType uint32 = defaultStreamType - var highestRes int = 0 - var lowestResType uint32 = defaultStreamType - var lowestRes int = 0 - - for _, video := range c.skill.Videos { - res := video.Width * video.Height - - // Highest Resolution - if res > highestRes { - highestRes = res - highestResType = uint32(video.StreamType) - } - + var highestResType uint32 = defaultStreamType + var highestRes int = 0 + var lowestResType uint32 = defaultStreamType + var lowestRes int = 0 + + for _, video := range c.skill.Videos { + res := video.Width * video.Height + + // Highest Resolution + if res > highestRes { + highestRes = res + highestResType = uint32(video.StreamType) + } + // Lower Resolution (or first if not set yet) - if lowestRes == 0 || res < lowestRes { - lowestRes = res - lowestResType = uint32(video.StreamType) - } - } - - // Return the streamType based on the selection - switch streamChoice { - case "main": - return highestResType - case "sub": - return lowestResType - default: - return defaultStreamType - } + if lowestRes == 0 || res < lowestRes { + lowestRes = res + lowestResType = uint32(video.StreamType) + } + } + + // Return the streamType based on the selection + switch streamChoice { + case "main": + return highestResType + case "sub": + return lowestResType + default: + return defaultStreamType + } } -func(c *TuyaClient) calBusinessSign(ts int64) string { +func (c *TuyaClient) calBusinessSign(ts int64) string { data := fmt.Sprintf("%s%s%s%d", c.clientId, c.accessToken, c.clientSecret, ts) val := md5.Sum([]byte(data)) res := fmt.Sprintf("%X", val) @@ -527,4 +527,4 @@ func contains(slice []int, val int) bool { } } return false -} \ No newline at end of file +} diff --git a/pkg/tuya/client.go b/pkg/tuya/client.go index 7b1406ea..ef9cbcc2 100644 --- a/pkg/tuya/client.go +++ b/pkg/tuya/client.go @@ -14,18 +14,18 @@ import ( ) type Client struct { - api *TuyaClient - prod core.Producer - done chan struct{} + api *TuyaClient + prod core.Producer + done chan struct{} } const ( - DefaultCnURL = "openapi.tuyacn.com" - DefaultWestUsURL = "openapi.tuyaus.com" - DefaultEastUsURL = "openapi-ueaz.tuyaus.com" + DefaultCnURL = "openapi.tuyacn.com" + DefaultWestUsURL = "openapi.tuyaus.com" + DefaultEastUsURL = "openapi-ueaz.tuyaus.com" DefaultCentralEuURL = "openapi.tuyaeu.com" - DefaultWestEuURL = "openapi-weaz.tuyaeu.com" - DefaultInURL = "openapi.tuyain.com" + DefaultWestEuURL = "openapi-weaz.tuyaeu.com" + DefaultInURL = "openapi.tuyain.com" ) func Dial(rawURL string) (core.Producer, error) { @@ -77,7 +77,7 @@ func Dial(rawURL string) (core.Producer, error) { } client := &Client{ - api: tuyaAPI, + api: tuyaAPI, done: make(chan struct{}), } @@ -93,7 +93,7 @@ func Dial(rawURL string) (core.Producer, error) { return streams.GetProducer(client.api.hlsURL) } else { conf := pion.Configuration{ - ICEServers: client.api.iceServers, + ICEServers: client.api.iceServers, ICETransportPolicy: pion.ICETransportPolicyAll, BundlePolicy: pion.BundlePolicyMaxBundle, } @@ -138,12 +138,12 @@ func Dial(rawURL string) (core.Producer, error) { client.Stop() return } - + if err = prod.SetAnswer(answer.Sdp); err != nil { client.Stop() return } - + prod.SDP = answer.Sdp } @@ -159,7 +159,7 @@ func Dial(rawURL string) (core.Producer, error) { client.api.mqtt.handleDisconnect = func() { client.Stop() } - + client.api.mqtt.handleError = func(err error) { // fmt.Printf("tuya: error: %s\n", err.Error()) client.Stop() diff --git a/pkg/tuya/mqtt.go b/pkg/tuya/mqtt.go index fbd50021..bf9badd7 100644 --- a/pkg/tuya/mqtt.go +++ b/pkg/tuya/mqtt.go @@ -11,67 +11,67 @@ import ( ) type TuyaMQTT struct { - client mqtt.Client - waiter core.Waiter - publishTopic string - subscribeTopic string - uid string - closed bool - handleAnswer func(answer AnswerFrame) - handleCandidate func(candidate CandidateFrame) - handleDisconnect func() - handleError func(err error) + client mqtt.Client + waiter core.Waiter + publishTopic string + subscribeTopic string + uid string + closed bool + handleAnswer func(answer AnswerFrame) + handleCandidate func(candidate CandidateFrame) + handleDisconnect func() + handleError func(err error) } type MqttFrameHeader struct { - Type string `json:"type"` - From string `json:"from"` - To string `json:"to"` - SubDevID string `json:"sub_dev_id"` - SessionID string `json:"sessionid"` - MotoID string `json:"moto_id"` - TransactionID string `json:"tid"` + Type string `json:"type"` + From string `json:"from"` + To string `json:"to"` + SubDevID string `json:"sub_dev_id"` + SessionID string `json:"sessionid"` + MotoID string `json:"moto_id"` + TransactionID string `json:"tid"` } type MqttFrame struct { - Header MqttFrameHeader `json:"header"` - Message json.RawMessage `json:"msg"` + Header MqttFrameHeader `json:"header"` + Message json.RawMessage `json:"msg"` } type OfferFrame struct { - Mode string `json:"mode"` - Sdp string `json:"sdp"` - StreamType uint32 `json:"stream_type"` - Auth string `json:"auth"` + Mode string `json:"mode"` + Sdp string `json:"sdp"` + StreamType uint32 `json:"stream_type"` + Auth string `json:"auth"` } type AnswerFrame struct { - Mode string `json:"mode"` - Sdp string `json:"sdp"` + Mode string `json:"mode"` + Sdp string `json:"sdp"` } type CandidateFrame struct { - Mode string `json:"mode"` - Candidate string `json:"candidate"` + Mode string `json:"mode"` + Candidate string `json:"candidate"` } type ResolutionFrame struct { - Mode string `json:"mode"` - Value int `json:"value"` + Mode string `json:"mode"` + Value int `json:"value"` } type DisconnectFrame struct { - Mode string `json:"mode"` + Mode string `json:"mode"` } type MqttMessage struct { - Protocol int `json:"protocol"` - Pv string `json:"pv"` - T int64 `json:"t"` - Data MqttFrame `json:"data"` + Protocol int `json:"protocol"` + Pv string `json:"pv"` + T int64 `json:"t"` + Data MqttFrame `json:"data"` } -func(c *TuyaClient) StartMQTT() error { +func (c *TuyaClient) StartMQTT() error { hubConfig, err := c.LoadHubConfig() if err != nil { return err @@ -106,14 +106,14 @@ func(c *TuyaClient) StartMQTT() error { return nil } -func(c *TuyaClient) StopMQTT() { +func (c *TuyaClient) StopMQTT() { if c.mqtt.client != nil { c.sendDisconnect() c.mqtt.client.Disconnect(1000) } } -func(c *TuyaClient) onConnect(client mqtt.Client) { +func (c *TuyaClient) onConnect(client mqtt.Client) { if token := client.Subscribe(c.mqtt.subscribeTopic, 1, c.consume); token.Wait() && token.Error() != nil { c.mqtt.waiter.Done(token.Error()) return @@ -122,7 +122,7 @@ func(c *TuyaClient) onConnect(client mqtt.Client) { c.mqtt.waiter.Done(nil) } -func(c *TuyaClient) consume(client mqtt.Client, msg mqtt.Message) { +func (c *TuyaClient) consume(client mqtt.Client, msg mqtt.Message) { var rmqtt MqttMessage if err := json.Unmarshal(msg.Payload(), &rmqtt); err != nil { c.mqtt.onError(fmt.Errorf("unmarshal mqtt message fail: %s, payload: %s", err.Error(), string(msg.Payload()))) @@ -143,7 +143,7 @@ func(c *TuyaClient) consume(client mqtt.Client, msg mqtt.Message) { } } -func(c *TuyaMQTT) onMqttAnswer(msg *MqttMessage) { +func (c *TuyaMQTT) onMqttAnswer(msg *MqttMessage) { var answerFrame AnswerFrame if err := json.Unmarshal(msg.Data.Message, &answerFrame); err != nil { c.onError(fmt.Errorf("unmarshal mqtt answer frame fail: %s, session: %s, frame: %s", @@ -152,11 +152,11 @@ func(c *TuyaMQTT) onMqttAnswer(msg *MqttMessage) { string(msg.Data.Message))) return } - + c.onAnswer(answerFrame) } -func(c *TuyaMQTT) onMqttCandidate(msg *MqttMessage) { +func (c *TuyaMQTT) onMqttCandidate(msg *MqttMessage) { var candidateFrame CandidateFrame if err := json.Unmarshal(msg.Data.Message, &candidateFrame); err != nil { c.onError(fmt.Errorf("unmarshal mqtt candidate frame fail: %s, session: %s, frame: %s", @@ -173,30 +173,30 @@ func(c *TuyaMQTT) onMqttCandidate(msg *MqttMessage) { c.onCandidate(candidateFrame) } -func(c *TuyaMQTT) onMqttDisconnect() { +func (c *TuyaMQTT) onMqttDisconnect() { c.closed = true c.onDisconnect() } -func(c *TuyaMQTT) onAnswer(answer AnswerFrame) { +func (c *TuyaMQTT) onAnswer(answer AnswerFrame) { if c.handleAnswer != nil { c.handleAnswer(answer) } } -func(c *TuyaMQTT) onCandidate(candidate CandidateFrame) { +func (c *TuyaMQTT) onCandidate(candidate CandidateFrame) { if c.handleCandidate != nil { c.handleCandidate(candidate) } } -func(c *TuyaMQTT) onDisconnect() { +func (c *TuyaMQTT) onDisconnect() { if c.handleDisconnect != nil { c.handleDisconnect() } } -func(c *TuyaMQTT) onError(err error) { +func (c *TuyaMQTT) onError(err error) { if c.handleError != nil { c.handleError(err) } @@ -220,12 +220,12 @@ func (c *TuyaClient) sendCandidate(candidate string) { func (c *TuyaClient) sendResolution(resolution int) { c.sendMqttMessage("resolution", 302, "", ResolutionFrame{ - Mode: "webrtc", - Value: resolution, + Mode: "webrtc", + Value: resolution, }) } -func(c *TuyaClient) sendDisconnect() { +func (c *TuyaClient) sendDisconnect() { c.sendMqttMessage("disconnect", 302, "", DisconnectFrame{ Mode: "webrtc", })