Skip to content

Commit

Permalink
0.9.5
Browse files Browse the repository at this point in the history
- modyfied postRequest method to be able to use only token on header
- modyfied __constructor of devices to take json saved data
- added setDeviceStatus method to update parameters of the device
- updated README
- create pre-release
  • Loading branch information
PJanisio committed Jun 12, 2024
1 parent af092d3 commit ed6adbf
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 34 deletions.
38 changes: 29 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
# ewelinkApiPhp

API connector for Sonoff devices using OAuth2.
API connector for Sonoff/ewelink devices using simple webapi based on OAuth2.

PHP 7.4+ required, no other dependencies.
PHP 7.4+, no other dependiencies required.

Version **0.9.5** is currently operative and ***pre released***, but not yet tested in 100%, so feedback is appreciated **create issues / PR** if needed.

## Current features

- login and authorization to ewelink (with refresh token)
- get devices list with all parameters
- saving devices to .json
- search value of parameter for each device (f.e switch status, productName etc.)
- update parameter of device

## Public key and secret

Expand All @@ -14,24 +24,34 @@ And put your keys and redirect Url in **Constants.php**

```
project_root/
├── src/
├── Constants.php
├── HttpClient.php
└── Utils.php
| └── Devices.php
│ ├── Constants.php
│ ├── HttpClient.php
│ └── Utils.php
| └── Devices.php
└── index.php
```

All classes are located in src directory.

Index.php works as a gateway to API and also as a debug for all methods.
Index.php works as a gateway to API and also as a debug for all availablemethods.

.json outputs will be saved in project_root
.json files outputs will be saved in project_root

## Example

See **index.php**
Examples will follow with stable release, for now - see **index.php**

## More inside info

- with next stable release methods and invoking functions structure can be changed (keep this in mind)
- branch **websockets** will probably be not maintened
- there could be some incosistency in the code still, like f.e handling error messages
11 changes: 9 additions & 2 deletions index.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ function getQueryParam($name) {
echo '<h1>Devices Data</h1>';
echo '<pre>' . print_r($devicesData, true) . '</pre>';

$devices = new Devices($httpClient);
$devices = new Devices();
echo '<h1>Loaded Devices Data</h1>';
echo '<pre>' . print_r($devices->getDevicesData(), true) . '</pre>';

Expand All @@ -59,9 +59,16 @@ function getQueryParam($name) {

// Example usage of getDeviceParamLive
$liveParam = 'switch'; // example parameter to get
$liveResult = $devices->getDeviceParamLive($deviceId, $liveParam);
$liveResult = $devices->getDeviceParamLive($httpClient, $deviceId, $liveParam);
echo '<h1>Live Device Parameter</h1>';
echo '<pre>' . print_r($liveResult, true) . '</pre>';

// Example usage of setDeviceStatus
$params = ['switch' => 'on']; // example parameters to update
$setStatusResult = $devices->setDeviceStatus($httpClient, $deviceId, $params);
echo '<h1>Set Device Status Result</h1>';
echo '<pre>' . print_r($setStatusResult, true) . '</pre>';

} catch (Exception $e) {
echo 'Error: ' . $e->getMessage();
}
Expand Down
66 changes: 60 additions & 6 deletions src/Devices.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

class Devices {
private $devicesData;
private $httpClient;

public function __construct(HttpClient $httpClient) {
$this->httpClient = $httpClient;
$this->loadDevicesData();
public function __construct() {
if (file_exists('devices.json')) {
$this->devicesData = json_decode(file_get_contents('devices.json'), true);
}
}

/**
Expand All @@ -20,6 +20,15 @@ private function loadDevicesData() {
}
}

/**
* Get the stored devices data.
*
* @return array|null The devices data or null if not set.
*/
public function getDevicesDataFromStorage() {
return $this->devicesData;
}

/**
* Get the loaded devices data.
*
Expand Down Expand Up @@ -96,20 +105,21 @@ public function searchDeviceParam($searchKey, $deviceId) {
/**
* Get live device parameter using the API.
*
* @param HttpClient $httpClient The HTTP client instance.
* @param string $deviceId The ID of the device.
* @param string $param The parameter to get.
* @param int $type The type (default is 1).
* @return mixed The specific parameter value from the API response or null if not found.
*/
public function getDeviceParamLive($deviceId, $param, $type = 1) {
public function getDeviceParamLive(HttpClient $httpClient, $deviceId, $param, $type = 1) {
$endpoint = '/v2/device/thing/status';
$queryParams = [
'id' => $deviceId,
'type' => $type,
'params' => urlencode($param)
];

$response = $this->httpClient->getRequest($endpoint, $queryParams);
$response = $httpClient->getRequest($endpoint, $queryParams);

if (isset($response['error']) && $response['error'] != 0) {
throw new Exception('Error: ' . $response['msg']);
Expand All @@ -121,4 +131,48 @@ public function getDeviceParamLive($deviceId, $param, $type = 1) {

return null;
}

/**
* Set the device status by updating a parameter.
*
* @param HttpClient $httpClient The HTTP client instance.
* @param string $deviceId The ID of the device.
* @param array $params The parameters to update.
* @return string The result message.
* @throws Exception If the parameter update fails.
*/
public function setDeviceStatus(HttpClient $httpClient, $deviceId, $params) {
// Check if the parameter exists and get the current value
foreach ($params as $param => $newValue) {
$currentValue = $this->getDeviceParamLive($httpClient, $deviceId, $param);
if ($currentValue === null) {
return "Parameter $param does not exist for device $deviceId.";
}

// Compare the current value with the new value
if ($currentValue == $newValue) {
return "Parameter $param is already set to $newValue for device $deviceId.";
}

// Update the parameter
$data = [
'type' => 1,
'id' => $deviceId,
'params' => [$param => $newValue]
];
$response = $httpClient->postRequest('/v2/device/thing/status', $data, true);

if (!isset($response['error']) || $response['error'] !== 0) {
throw new Exception('Failed to update parameter: ' . ($response['msg'] ?? 'Unknown error'));
}

// Verify the update
$updatedValue = $this->getDeviceParamLive($httpClient, $deviceId, $param);
if ($updatedValue == $newValue) {
return "Parameter $param successfully updated to $newValue for device $deviceId.";
} else {
return "Failed to update parameter $param to $newValue for device $deviceId. Current value is $updatedValue.";
}
}
}
}
41 changes: 24 additions & 17 deletions src/HttpClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public function __construct($state) {
$utils = new Utils();
$this->region = Constants::REGION; // Assign region from Constants
$this->loginUrl = $this->createLoginUrl($state);

list($this->code, $redirectRegion) = $utils->handleRedirect();
if ($redirectRegion) {
$this->region = $redirectRegion;
Expand Down Expand Up @@ -106,38 +107,44 @@ public function getGatewayUrl() {
}

/**
* Make an HTTP POST request with the given endpoint and data.
* Make a POST request.
*
* @param string $endpoint The endpoint to make the request to.
* @param array $data The data to send in the request.
* @param string $endpoint The endpoint to send the request to.
* @param array $data The data to send in the request body.
* @param bool $useTokenAuthorization Whether to use token-based authorization.
* @return array The response data.
* @throws Exception If the request fails.
* @throws Exception If there is an error in the request.
*/
public function postRequest($endpoint, $data = []) {
$url = $this->getGatewayUrl() . $endpoint;
public function postRequest($endpoint, $data, $useTokenAuthorization = false) {
$utils = new Utils();
$nonce = $utils->generateNonce();
$body = json_encode($data);
$authorization = 'Sign ' . $utils->sign($body, Constants::APP_SECRET);

$url = $this->getGatewayUrl() . $endpoint;
$headers = [
"Content-type: application/json; charset=utf-8",
"X-CK-Appid: " . Constants::APPID,
"Authorization: " . $authorization,
"X-CK-Nonce: " . $nonce
"X-CK-Nonce: " . $utils->generateNonce()
];

if ($useTokenAuthorization) {
$token = $this->tokenData['accessToken'];
$headers[] = "Authorization: Bearer $token";
} else {
$authorization = $utils->sign(json_encode($data), Constants::APP_SECRET);
$headers[] = "Authorization: Sign $authorization";
}

$options = [
'http' => [
'header' => implode("\r\n", $headers) . "\r\n",
'method' => 'POST',
'content' => $body,
'header' => implode("\r\n", $headers),
'method' => 'POST',
'content' => json_encode($data),
],
];
$context = stream_context_create($options);

$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);

if ($result === FALSE) {
throw new Exception('Error in request');
throw new Exception('Error making POST request');
}

$response = json_decode($result, true);
Expand Down

0 comments on commit ed6adbf

Please sign in to comment.