refactor
This commit is contained in:
@@ -568,14 +568,14 @@ Tested: KD110, KC200, KC401, KC420WS, EC71.
|
|||||||
|
|
||||||
#### Source: Tuya
|
#### Source: Tuya
|
||||||
|
|
||||||
[Tuya](https://www.tuya.com/) proprietary camera protocol with **two way audio** support. Go2rtc supports `Cloud API` and `Tuya API`.
|
[Tuya](https://www.tuya.com/) proprietary camera protocol with **two way audio** support. Go2rtc supports `Tuya Cloud API` and `Tuya Smart API`.
|
||||||
|
|
||||||
The `Cloud API` requires setting up a cloud project in the Tuya Developer Platform to retrieve the required credentials. The `Tuya API` does not require a cloud project and the cameras can be added through the interface via email/password.
|
The `Tuya Cloud API` requires setting up a cloud project in the Tuya Developer Platform to retrieve the required credentials. The `Tuya Smart API` does not require a cloud project and the cameras can be added through the interface via email/password.
|
||||||
|
|
||||||
**Cloud API**:
|
**Tuya Cloud API**:
|
||||||
- Obtain `device_id`, `client_id`, `client_secret`, and `uid` from [Tuya IoT Platform](https://iot.tuya.com/). [Here's a guide](https://xzetsubou.github.io/hass-localtuya/cloud_api/).
|
- Obtain `device_id`, `client_id`, `client_secret`, and `uid` from [Tuya IoT Platform](https://iot.tuya.com/). [Here's a guide](https://xzetsubou.github.io/hass-localtuya/cloud_api/).
|
||||||
|
|
||||||
**Open API**:
|
**Tuya Smart API**:
|
||||||
- Smart Life accounts are not supported, you need to create a Tuya account. If the cameras are already added to the Smart Life app, you need to remove them and add them again to the Tuya Smart app.
|
- Smart Life accounts are not supported, you need to create a Tuya account. If the cameras are already added to the Smart Life app, you need to remove them and add them again to the Tuya Smart app.
|
||||||
|
|
||||||
**Configuring the stream:**
|
**Configuring the stream:**
|
||||||
@@ -585,19 +585,19 @@ The `Cloud API` requires setting up a cloud project in the Tuya Developer Platfo
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
streams:
|
streams:
|
||||||
# Cloud API: WebRTC main stream
|
# Tuya Cloud API: WebRTC main stream
|
||||||
tuya_webrtc:
|
tuya_webrtc:
|
||||||
- tuya://openapi.tuyaus.com?device_id=XXX&uid=XXX&client_id=XXX&client_secret=XXX
|
- tuya://openapi.tuyaus.com?device_id=XXX&uid=XXX&client_id=XXX&client_secret=XXX
|
||||||
|
|
||||||
# Cloud API: WebRTC sub stream
|
# Tuya Cloud API: WebRTC sub stream
|
||||||
tuya_webrtc_sd:
|
tuya_webrtc_sd:
|
||||||
- tuya://openapi.tuyaus.com?device_id=XXX&uid=XXX&client_id=XXX&client_secret=XXX&resolution=sd
|
- tuya://openapi.tuyaus.com?device_id=XXX&uid=XXX&client_id=XXX&client_secret=XXX&resolution=sd
|
||||||
|
|
||||||
# Tuya API: WebRTC main stream
|
# Tuya Smart API: WebRTC main stream
|
||||||
tuya:
|
tuya:
|
||||||
- tuya://protect-us.ismartlife.me?device_id=XXX&email=XXX&password=XXX
|
- tuya://protect-us.ismartlife.me?device_id=XXX&email=XXX&password=XXX
|
||||||
|
|
||||||
# Tuya API: WebRTC sub stream
|
# Tuya Smart API: WebRTC sub stream
|
||||||
tuya:
|
tuya:
|
||||||
- tuya://protect-us.ismartlife.me?device_id=XXX&email=XXX&password=XXX&resolution=sd
|
- tuya://protect-us.ismartlife.me?device_id=XXX&email=XXX&password=XXX&resolution=sd
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ func apiTuya(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
tuyaAPI, err := tuya.NewTuyaApiClient(
|
tuyaAPI, err := tuya.NewTuyaSmartApiClient(
|
||||||
httpClient,
|
httpClient,
|
||||||
tuyaRegion.Host,
|
tuyaRegion.Host,
|
||||||
email,
|
email,
|
||||||
|
|||||||
+3
-3
@@ -49,11 +49,11 @@ func Dial(rawURL string) (core.Producer, error) {
|
|||||||
|
|
||||||
query := u.Query()
|
query := u.Query()
|
||||||
|
|
||||||
// Tuya API
|
// Tuya Smart API
|
||||||
email := query.Get("email")
|
email := query.Get("email")
|
||||||
password := query.Get("password")
|
password := query.Get("password")
|
||||||
|
|
||||||
// Cloud API
|
// Tuya Cloud API
|
||||||
uid := query.Get("uid")
|
uid := query.Get("uid")
|
||||||
clientId := query.Get("client_id")
|
clientId := query.Get("client_id")
|
||||||
clientSecret := query.Get("client_secret")
|
clientSecret := query.Get("client_secret")
|
||||||
@@ -80,7 +80,7 @@ func Dial(rawURL string) (core.Producer, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if useTuyaApi {
|
if useTuyaApi {
|
||||||
if client.api, err = NewTuyaApiClient(nil, u.Hostname(), email, password, deviceId); err != nil {
|
if client.api, err = NewTuyaSmartApiClient(nil, u.Hostname(), email, password, deviceId); err != nil {
|
||||||
return nil, fmt.Errorf("tuya: %w", err)
|
return nil, fmt.Errorf("tuya: %w", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -121,12 +121,12 @@ type AppInfo struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type MQTTConfigResponse struct {
|
type MQTTConfigResponse struct {
|
||||||
Result TuyaApiMQTTConfig `json:"result"`
|
Result SmartApiMQTTConfig `json:"result"`
|
||||||
Success bool `json:"success"`
|
Success bool `json:"success"`
|
||||||
Msg string `json:"errorMsg,omitempty"`
|
Msg string `json:"errorMsg,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TuyaApiMQTTConfig struct {
|
type SmartApiMQTTConfig struct {
|
||||||
Msid string `json:"msid"`
|
Msid string `json:"msid"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
}
|
}
|
||||||
@@ -203,18 +203,18 @@ type Device struct {
|
|||||||
Uuid string `json:"uuid"`
|
Uuid string `json:"uuid"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TuyaApiWebRTCConfigRequest struct {
|
type SmartApiWebRTCConfigRequest struct {
|
||||||
DevId string `json:"devId"`
|
DevId string `json:"devId"`
|
||||||
ClientTraceId string `json:"clientTraceId"`
|
ClientTraceId string `json:"clientTraceId"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TuyaApiWebRTCConfigResponse struct {
|
type SmartApiWebRTCConfigResponse struct {
|
||||||
Result TuyaWebRTCConfig `json:"result"`
|
Result SmartApiWebRTCConfig `json:"result"`
|
||||||
Success bool `json:"success"`
|
Success bool `json:"success"`
|
||||||
Msg string `json:"errorMsg,omitempty"`
|
Msg string `json:"errorMsg,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TuyaWebRTCConfig struct {
|
type SmartApiWebRTCConfig struct {
|
||||||
AudioAttributes AudioAttributes `json:"audioAttributes"`
|
AudioAttributes AudioAttributes `json:"audioAttributes"`
|
||||||
Auth string `json:"auth"`
|
Auth string `json:"auth"`
|
||||||
GatewayId string `json:"gatewayId"`
|
GatewayId string `json:"gatewayId"`
|
||||||
@@ -234,7 +234,7 @@ type TuyaWebRTCConfig struct {
|
|||||||
VideoClarity int `json:"videoClarity"`
|
VideoClarity int `json:"videoClarity"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TuyaApiClient struct {
|
type TuyaSmartApiClient struct {
|
||||||
TuyaClient
|
TuyaClient
|
||||||
|
|
||||||
email string
|
email string
|
||||||
@@ -259,7 +259,7 @@ var AvailableRegions = []Region{
|
|||||||
{"india", "protect-in.ismartlife.me", "India", "IN"},
|
{"india", "protect-in.ismartlife.me", "India", "IN"},
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTuyaApiClient(httpClient *http.Client, baseUrl, email, password, deviceId string) (*TuyaApiClient, error) {
|
func NewTuyaSmartApiClient(httpClient *http.Client, baseUrl, email, password, deviceId string) (*TuyaSmartApiClient, error) {
|
||||||
var region *Region
|
var region *Region
|
||||||
for _, r := range AvailableRegions {
|
for _, r := range AvailableRegions {
|
||||||
if r.Host == baseUrl {
|
if r.Host == baseUrl {
|
||||||
@@ -278,7 +278,7 @@ func NewTuyaApiClient(httpClient *http.Client, baseUrl, email, password, deviceI
|
|||||||
|
|
||||||
mqttClient := NewTuyaMqttClient(deviceId)
|
mqttClient := NewTuyaMqttClient(deviceId)
|
||||||
|
|
||||||
client := &TuyaApiClient{
|
client := &TuyaSmartApiClient{
|
||||||
TuyaClient: TuyaClient{
|
TuyaClient: TuyaClient{
|
||||||
httpClient: httpClient,
|
httpClient: httpClient,
|
||||||
mqtt: mqttClient,
|
mqtt: mqttClient,
|
||||||
@@ -295,7 +295,7 @@ func NewTuyaApiClient(httpClient *http.Client, baseUrl, email, password, deviceI
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WebRTC Flow
|
// WebRTC Flow
|
||||||
func (c *TuyaApiClient) Init() error {
|
func (c *TuyaSmartApiClient) Init() error {
|
||||||
if err := c.initToken(); err != nil {
|
if err := c.initToken(); err != nil {
|
||||||
return fmt.Errorf("failed to initialize token: %w", err)
|
return fmt.Errorf("failed to initialize token: %w", err)
|
||||||
}
|
}
|
||||||
@@ -317,11 +317,11 @@ func (c *TuyaApiClient) Init() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TuyaApiClient) GetStreamUrl(streamType string) (streamUrl string, err error) {
|
func (c *TuyaSmartApiClient) GetStreamUrl(streamType string) (streamUrl string, err error) {
|
||||||
return "", errors.New("not supported")
|
return "", errors.New("not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TuyaApiClient) GetAppInfo() (*AppInfoResponse, error) {
|
func (c *TuyaSmartApiClient) GetAppInfo() (*AppInfoResponse, error) {
|
||||||
url := fmt.Sprintf("https://%s/api/customized/web/app/info", c.baseUrl)
|
url := fmt.Sprintf("https://%s/api/customized/web/app/info", c.baseUrl)
|
||||||
|
|
||||||
body, err := c.request("POST", url, nil)
|
body, err := c.request("POST", url, nil)
|
||||||
@@ -341,7 +341,7 @@ func (c *TuyaApiClient) GetAppInfo() (*AppInfoResponse, error) {
|
|||||||
return &appInfoResponse, nil
|
return &appInfoResponse, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TuyaApiClient) GetHomeList() (*HomeListResponse, error) {
|
func (c *TuyaSmartApiClient) GetHomeList() (*HomeListResponse, error) {
|
||||||
url := fmt.Sprintf("https://%s/api/new/common/homeList", c.baseUrl)
|
url := fmt.Sprintf("https://%s/api/new/common/homeList", c.baseUrl)
|
||||||
|
|
||||||
body, err := c.request("POST", url, nil)
|
body, err := c.request("POST", url, nil)
|
||||||
@@ -361,7 +361,7 @@ func (c *TuyaApiClient) GetHomeList() (*HomeListResponse, error) {
|
|||||||
return &homeListResponse, nil
|
return &homeListResponse, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TuyaApiClient) GetSharedHomeList() (*SharedHomeListResponse, error) {
|
func (c *TuyaSmartApiClient) GetSharedHomeList() (*SharedHomeListResponse, error) {
|
||||||
url := fmt.Sprintf("https://%s/api/new/playback/shareList", c.baseUrl)
|
url := fmt.Sprintf("https://%s/api/new/playback/shareList", c.baseUrl)
|
||||||
|
|
||||||
body, err := c.request("POST", url, nil)
|
body, err := c.request("POST", url, nil)
|
||||||
@@ -381,7 +381,7 @@ func (c *TuyaApiClient) GetSharedHomeList() (*SharedHomeListResponse, error) {
|
|||||||
return &sharedHomeListResponse, nil
|
return &sharedHomeListResponse, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TuyaApiClient) GetRoomList(homeId string) (*RoomListResponse, error) {
|
func (c *TuyaSmartApiClient) GetRoomList(homeId string) (*RoomListResponse, error) {
|
||||||
url := fmt.Sprintf("https://%s/api/new/common/roomList", c.baseUrl)
|
url := fmt.Sprintf("https://%s/api/new/common/roomList", c.baseUrl)
|
||||||
|
|
||||||
data := RoomListRequest{
|
data := RoomListRequest{
|
||||||
@@ -405,7 +405,7 @@ func (c *TuyaApiClient) GetRoomList(homeId string) (*RoomListResponse, error) {
|
|||||||
return &roomListResponse, nil
|
return &roomListResponse, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TuyaApiClient) initToken() error {
|
func (c *TuyaSmartApiClient) initToken() error {
|
||||||
tokenUrl := fmt.Sprintf("https://%s/api/login/token", c.baseUrl)
|
tokenUrl := fmt.Sprintf("https://%s/api/login/token", c.baseUrl)
|
||||||
|
|
||||||
tokenReq := LoginTokenRequest{
|
tokenReq := LoginTokenRequest{
|
||||||
@@ -470,10 +470,10 @@ func (c *TuyaApiClient) initToken() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TuyaApiClient) loadWebrtcConfig() (*WebRTCConfig, error) {
|
func (c *TuyaSmartApiClient) loadWebrtcConfig() (*WebRTCConfig, error) {
|
||||||
url := fmt.Sprintf("https://%s/api/jarvis/config", c.baseUrl)
|
url := fmt.Sprintf("https://%s/api/jarvis/config", c.baseUrl)
|
||||||
|
|
||||||
data := TuyaApiWebRTCConfigRequest{
|
data := SmartApiWebRTCConfigRequest{
|
||||||
DevId: c.deviceId,
|
DevId: c.deviceId,
|
||||||
ClientTraceId: fmt.Sprintf("%x", rand.Int63()),
|
ClientTraceId: fmt.Sprintf("%x", rand.Int63()),
|
||||||
}
|
}
|
||||||
@@ -483,7 +483,7 @@ func (c *TuyaApiClient) loadWebrtcConfig() (*WebRTCConfig, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var webRTCConfigResponse TuyaApiWebRTCConfigResponse
|
var webRTCConfigResponse SmartApiWebRTCConfigResponse
|
||||||
err = json.Unmarshal(body, &webRTCConfigResponse)
|
err = json.Unmarshal(body, &webRTCConfigResponse)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -524,7 +524,7 @@ func (c *TuyaApiClient) loadWebrtcConfig() (*WebRTCConfig, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TuyaApiClient) loadHubConfig() (config *MQTTConfig, err error) {
|
func (c *TuyaSmartApiClient) loadHubConfig() (config *MQTTConfig, err error) {
|
||||||
mqttUrl := fmt.Sprintf("https://%s/api/jarvis/mqtt", c.baseUrl)
|
mqttUrl := fmt.Sprintf("https://%s/api/jarvis/mqtt", c.baseUrl)
|
||||||
|
|
||||||
mqttBody, err := c.request("POST", mqttUrl, nil)
|
mqttBody, err := c.request("POST", mqttUrl, nil)
|
||||||
@@ -552,7 +552,7 @@ func (c *TuyaApiClient) loadHubConfig() (config *MQTTConfig, err error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TuyaApiClient) request(method string, url string, body any) ([]byte, error) {
|
func (c *TuyaSmartApiClient) request(method string, url string, body any) ([]byte, error) {
|
||||||
var bodyReader io.Reader
|
var bodyReader io.Reader
|
||||||
if body != nil {
|
if body != nil {
|
||||||
jsonBody, err := json.Marshal(body)
|
jsonBody, err := json.Marshal(body)
|
||||||
Reference in New Issue
Block a user