I need help for adding individual schedules in my Tuya Weekly Schedule (PHP cURL)

146 Views Asked by At

I am working on a web site where users can control their thermostat, but I'm having difficulty with the schedule part. I can display it, but when I create a new schedule the temperature desired is not applied, but works in postman. Here's my code:

Script.php

class ConnectTuya
{
    private $_baseUrl;
    private $_deviceId;
    private $_clientId;
    private $_secret_key;
    private $_getToken;
    private $_fDevices;
    private $_aDevices;
    private $_bDevices;
    private $_t;
    
    public function __construct()
    {
        $this->_baseUrl = 'https://openapi.tuyaeu.com/';
        $this->_clientId  = 'xxxxxxxxxxxxxxxxxxxxxx'; 
        $this->_secret_key = 'xxxxxxxxxxxxxxxxxxxxxxxxxx';
        $this->_getToken = "v1.0/token?grant_type=1";
        $this->_t = round(microtime(true) * 1000);
        $this->_fDevices = 'v1.0/iot-03/devices/';
        $this->_aDevices = 'v1.0/devices/';
        $this->_bDevices = 'v2.0/cloud/timer/device/';
    }

    public function get_token()
    {
        $headers = array(
            'sign_method: HMAC-SHA256',
            'client_id: '.$this->_clientId,
            't: '.$this->_t,
            'Content-Type: application/json',
            'access_token:'
        );
        $url =  $this->_baseUrl . $this->_getToken;
        $sign = $this->build_sign('GET', $url, [], []);

        $headers[] = "sign: " . $sign;
        $curl = curl_init();
        curl_setopt_array($curl, array(
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => '',
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 0,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => 'GET',
            CURLOPT_HTTPHEADER => $headers
        ));

        $response = curl_exec($curl);

        curl_close($curl);
        return json_decode($response, true);
    }
    public function get_specification($device_id,  $access_token)
    {
        $headers = array(
            'sign_method: HMAC-SHA256',
            'client_id: '.$this->_clientId,
            't: '.$this->_t,
            'Content-Type: application/json',
            'access_token: ' . $access_token
        );
        $method = 'GET';
        $payload = array(
            'device_id' => $device_id
        );
        $url =  $this->_baseUrl . $this->_fDevices . $device_id . '/specification';
        $sign = $this->build_sign($method, $url, [], [], $access_token);

        $headers[] = "sign: " . $sign;
        $curl = curl_init();
        curl_setopt_array($curl, array(
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => '',
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 0,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => $method,
            CURLOPT_HTTPHEADER => $headers
        ));

        $response = curl_exec($curl);

        curl_close($curl);
        return json_decode($response, true);
    }

    public function send_commands($device_id, $commands ,$access_token)
    {
        $headers = array(
            'sign_method: HMAC-SHA256',
            'client_id: '.$this->_clientId,
            't: '.$this->_t,
            'Content-Type: application/json',
            'access_token: ' . $access_token
        );
        $method = 'POST';
        if (empty($commands)) {
            return false;
        }
        $payload = array(
            "commands" => $commands
        );
        $url =  $this->_baseUrl . $this->_fDevices . $device_id . '/commands';
        $sign = $this->build_sign($method, $url, $payload, [], $access_token);

        $headers[] = "sign: " . $sign;
        $curl = curl_init();
        curl_setopt_array($curl, array(
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => '',
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 0,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => $method,
            CURLOPT_POSTFIELDS =>json_encode($payload),
            CURLOPT_HTTPHEADER => $headers
        ));

        $response = curl_exec($curl);

        curl_close($curl);
        return json_decode($response, true);
    }

    public function get_scheduled($device_id,  $access_token)
    {
        $headers = array(
            'sign_method: HMAC-SHA256',
            'client_id: '.$this->_clientId,
            't: '.$this->_t,
            'Content-Type: application/json',
            'access_token: ' . $access_token
        );
        $method = 'GET';
        $payload = array(
            'device_id' => $device_id
        );
        $url =  $this->_baseUrl . $this->_bDevices . $device_id ;
        $sign = $this->build_sign($method, $url, [], [], $access_token);

        $headers[] = "sign: " . $sign;
        $curl = curl_init();
        curl_setopt_array($curl, array(
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => '',
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 0,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => $method,
            CURLOPT_HTTPHEADER => $headers
        ));

        $response = curl_exec($curl);

        curl_close($curl);
        return json_decode($response, true);
    }

    public function add_scheduled($device_id,$temp_add, $time, $loops, $access_token) {
        $headers = array(
            'sign_method: HMAC-SHA256',
            'client_id: ' . $this->_clientId,
            't: ' . $this->_t,
            'Content-Type: application/json',
            'access_token: ' . $access_token
        );
    
        $method = 'POST';
        
        $payload = array(
            "alias_name" => "Scheduled",
            "category" => "Scheduled",
            "time" => $time,
            "timezone_id" => "Europe/Paris",
            "loops" => $loops,
            "functions" => array(
                array(
                    "code" => "switch_1",
                    "value" => true
                ),
                array(
                    "code" => "temp_set",
                    "value" => array("Value" =>strval($temp_add))
                ),
                array(
                    "code" => "customize_mode_switch",
                    "value" => true
                )
            )
        );
        
        $url =  $this->_baseUrl . $this->_bDevices . $device_id;
        $sign = $this->build_sign($method, $url, $payload, [], $access_token);

        $headers[] = "sign: " . $sign;
        $curl = curl_init();
        curl_setopt_array($curl, array(
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => '',
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 0,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => $method,
            CURLOPT_POSTFIELDS => json_encode($payload),
            CURLOPT_HTTPHEADER => $headers
        ));

        $response = curl_exec($curl);

        curl_close($curl);
        return json_decode($response, true);
    }
    
    
    
    

    public function get_device_information($device_id,  $access_token)
    {
        $headers = array(
            'sign_method: HMAC-SHA256',
            'client_id: '.$this->_clientId,
            't: '.$this->_t,
            'Content-Type: application/json',
            'access_token: ' . $access_token
        );
        $method = 'GET';
        $payload = array(
            'device_id' => $device_id
        );
        $url =  $this->_baseUrl . $this->_aDevices . $device_id . '/';
        $sign = $this->build_sign($method, $url, [], [], $access_token);

        $headers[] = "sign: " . $sign;
        $curl = curl_init();
        curl_setopt_array($curl, array(
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => '',
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 0,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => $method,
            CURLOPT_HTTPHEADER => $headers
        ));

        $response = curl_exec($curl);

        curl_close($curl);
        return json_decode($response, true);
    }

    public function delete_scheduled($device_id, $timer_id, $access_token) {
        $headers = array(
            'sign_method: HMAC-SHA256',
            'client_id: ' . $this->_clientId,
            't: ' . $this->_t,
            'Content-Type: application/json',
            'access_token: ' . $access_token
        );
        $method = 'DELETE';

        $url = $this->_baseUrl . $this->_bDevices . $device_id . '/batch?timer_ids=' . $timer_id;
        $sign = $this->build_sign($method, $url, [], [], $access_token);
    
        $headers[] = "sign: " . $sign;
        $curl = curl_init();
        curl_setopt_array($curl, array(
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => '',
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 0,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => $method,
            CURLOPT_HTTPHEADER => $headers
        ));
    
        $response = curl_exec($curl);
    
        curl_close($curl);
        return json_decode($response, true);
    }

    public function modeVacance($device_id,$access_token, $idVacance, $mode){
        $headers = array(
            'sign_method: HMAC-SHA256',
            'client_id: ' . $this->_clientId,
            't: ' . $this->_t,
            'Content-Type: application/json',
            'access_token: ' . $access_token
        );
        $method = 'PUT';
        $payload = array(
            "timer_id" => $idVacance,
            "enable" => $mode
        );
        $url = $this->_baseUrl . $this->_bDevices . $device_id . '/state';
        $sign = $this->build_sign($method, $url, $payload, [], $access_token);

        $headers[] = "sign: " . $sign;
        $curl = curl_init();
        curl_setopt_array($curl, array(
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => '',
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 0,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => $method,
            CURLOPT_POSTFIELDS =>json_encode($payload),
            CURLOPT_HTTPHEADER => $headers
        ));

        $response = curl_exec($curl);

        curl_close($curl);
        return json_decode($response, true);
    }
    public function modeVacanceOther($device_id,$access_token, $idVacance, $mode){
        $headers = array(
            'sign_method: HMAC-SHA256',
            'client_id: ' . $this->_clientId,
            't: ' . $this->_t,
            'Content-Type: application/json',
            'access_token: ' . $access_token
        );
        $method = 'PUT';
        $payload = array(
            "timer_id" => $idVacance,
            "enable" => $mode
        );
        $url = $this->_baseUrl . $this->_bDevices . $device_id . '/state';
        $sign = $this->build_sign($method, $url, $payload, [], $access_token);

        $headers[] = "sign: " . $sign;
        $curl = curl_init();
        curl_setopt_array($curl, array(
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => '',
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 0,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => $method,
            CURLOPT_POSTFIELDS =>json_encode($payload),
            CURLOPT_HTTPHEADER => $headers
        ));

        $response = curl_exec($curl);

        curl_close($curl);
        return json_decode($response, true);
    }
    public function add_scheduled_Vacence($device_id,$access_token){
        $headers = array(
            'sign_method: HMAC-SHA256',
            'client_id: ' . $this->_clientId,
            't: ' . $this->_t,
            'Content-Type: application/json',
            'access_token: ' . $access_token
        );
    
        $method = 'POST';
    
        $payload = array(
            "alias_name" => "Scheduled-Vacance",
            "category" => "Scheduled-Vacance",
            "time" => "00:00",
            "timezone_id" => "Europe/Paris",
            "loops" => "1111111",
            "functions" => array(
                array(
                    "code" => "switch_1",
                    "value" => true
                ),
                array(
                    "code" => "temp_set",
                    "value" => 120
                ),
                array(
                    "code" => "customize_mode_switch",
                    "value" => true
                )
            )
        );
    
        $url = $this->_baseUrl . $this->_bDevices . $device_id;
        $sign = $this->build_sign($method, $url, $payload, [], $access_token);
    
        $headers[] = "sign: " . $sign;
    
        $curl = curl_init();
        curl_setopt_array($curl, array(
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => '',
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 0,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => $method,
            CURLOPT_POSTFIELDS =>json_encode($payload),
            CURLOPT_HTTPHEADER => $headers
        ));
    
        $response = curl_exec($curl);
    
        curl_close($curl);
    
        return json_decode($response, true);
    }

    private function build_sign($method, $url ,$payload, $headers, $token = "")
    {
        $str_header = "";
        if ($headers) {
            $str_header = implode("\n", $headers);
        }
        $str_payload = "";
        if ($payload) {
            $str_payload = json_encode($payload);
        }

        $content_SHA256 = hash('sha256', $str_payload);
        
        $parse_url = parse_url($url);
        $part_url = empty($parse_url['path']) ? "" : $parse_url['path'];
        $query_url = empty($parse_url['query']) ? "" : "?" . $parse_url['query'];
        $str_to_sign = $method . "\n" . $content_SHA256 . "\n" . $str_header . "\n" . $part_url . $query_url;

        $sign = strtoupper(hash_hmac('SHA256', $this->_clientId . $token . $this->_t . $str_to_sign, $this->_secret_key));
        return $sign;
    }


}
$ConnexionTuya = new ConnectTuya();

The add_scheduled function is my only big problem

index.php

     if(isset ($_POST['time_add']) && isset ($_POST['day_add']) && isset ($_POST['temp_add'])){
            $time_add = $_POST['time_add'];
            $loops_add = $_POST['day_add'];
            $temp_add = $_POST['temp_add'];

            $time_add = strval($time_add);
            $loops_add = strval($loops_add);

            $add_schedule = $ConnexionTuya->add_scheduled($device_id,$temp_add, $time_add, $loops_add, $access_token['result']['access_token']);
            print_r($add_schedule);
        }

For the error I got it's when I do it in postman :


{
            "alias_name": "Scheduled",
            "category": "Scheduled",
            "date": "00000000",
            "enable": true,
            "functions": [
                {
                    "code": "switch_1",
                    "value": true
                },
                {
                    "code": "temp_set",
                    "value": {
                        "Value": "160.0"
                    }
                },
                {
                    "code": "customize_mode_switch",
                    "value": true
                }
            ],
            "loops": "0100000",
            "time": "08:00",
            "timer_id": "320383673",
            "timezone_id": "Europe/Paris"
        }

and if i do it in my web site :


{
            "alias_name": "Scheduled",
            "category": "Scheduled",
            "date": "00000000",
            "enable": true,
            "functions": [
                {
                    "code": "switch_1",
                    "value": true
                },
                {
                    "code": "temp_set",
                    "value": {
                        "value": "160.0"
                    }
                },
                {
                    "code": "customize_mode_switch",
                    "value": true
                }
            ],
            "loops": "0100000",
            "time": "12:48",
            "timer_id": "320385032",
            "timezone_id": "Europe/Paris"
        }

The issue is that when I execute my add_schedule function, it succeeds, but the result in the temp_set code sets the value as value:temp. For it to function properly, I require the value to be Value:temp.

I try using all I know and the GitHub of the script: https://github.com/hao159/tuya-connect-php

In postman:

postman

The web site:

website

Postman what is working and not working : postmanValue

Info in the web site: web site info

1

There are 1 best solutions below

4
Don't Panic On

If you check the send_commands() method, you can see that it passes the $payload to build_sign() as an array, not json_encode()d.

If you trace through build_sign(), you can see it json_encode()s the payload it receives.

But if you compare that to add_scheduled() - which I understand is the method that is not working - you are passing build_sign() an already json_encode()d payload. build_sign() will json_encode() that a second time, and I guess that is a problem.

Try passing the payload as the original array:

// Construct the signature
$sign = $this->build_sign($method, $url, $payload, $headers, $access_token);