diff --git a/docs/server-api-v1/devices.md b/docs/server-api-v1/devices.md index 48929ad..4497b65 100644 --- a/docs/server-api-v1/devices.md +++ b/docs/server-api-v1/devices.md @@ -32,13 +32,13 @@ --- -### GET `/api/v1/devices/scan` -Поиск новых устройств в сети +### GET `/api/v1/devices/scanning/setup` AND GET `/api/v1/devices/scanning/all` +Поиск новых устройств в сети (setup) или всех устройств в сети ### Пример ответа ```json { - "status": "ok", + "status": true, "devices": [ { "device_name": "Relay 1", @@ -54,14 +54,13 @@ --- -### POST `/api/v1/devices/new` +### POST `/api/v1/devices/setup/new-device` Добавление нового устройства ### Пример запроса ```json { "device_ip": "192.168.1.43", - "device_id": "ecf0a1b5c9d74f9a8e294c1f67b0a8b9", "alias": "alias_name_like_variable", // Must be uniq "name": "Реле помпы септика", "description": "Управляет помпой, должно периодически включаться и выключаться" @@ -71,21 +70,22 @@ ### Пример ответа ```json { - "status": "ok", - "device": { - "id": 12, - "alias": "alias_name_like_variable", + "status": true, + "data": { "device": { - "device_name": "Relay 1", - "device_type": "relay", - "firmware_version": "1.0.3", - "device_id": "ecf0a1b5c9d74f9a8e294c1f67b0a8b9", - "device_ip": "192.168.1.13" - }, - "name": "Реле помпы септика", - "description": "Управляет помпой, должно периодически включаться и выключаться", - "connection_state": "active", // active | lost - "last_contact": "2025-07-28 18:35" + "id": 12, + "alias": "...", + "device": { + "device_name": "Relay 1", + "device_type": "relay", + "firmware_version": "1.0.3", + "device_id": "ecf0a1b5c9d74f9a8e294c1f67b0a8b9", + "device_ip": "192.168.1.13" + // ... + }, + "name": "Реле помпы септика", + "description": "Управляет помпой, должно периодически включаться и выключаться", + } } } ``` @@ -93,35 +93,40 @@ ### Пример НЕ успешного ответа ```json { - "status": "error", - "field": "alias", // alias | name | device_ip | device_id - "message": "Alias already exists" // "Name can`t be empty" | "Device not found by IP" | "Wrong device ID" + "status": false, + "error_alias": "", + "failed_fields": ["alias"], // alias | name | device_id + "msg": "Alias already exists" // "Name can`t be empty" | "Device not found by IP" } ``` --- -### GET `/api/v1/devices/id/{{id}}` OR GET `/api/v1/devices/alias/{{alias}}` -Получить статус по отдельному девайсу +### GET `/api/v1/devices/id/{{id}}/info` +Получить информацию по отдельному девайсу ### Пример ответа ```json { - "status": "ok", - "device": { - "id": 12, - "alias": "...", + "status": true, + "data": { "device": { - "device_name": "Relay 1", - "device_type": "relay", - "firmware_version": "1.0.3", - "device_id": "ecf0a1b5c9d74f9a8e294c1f67b0a8b9", - "device_ip": "192.168.1.13" - }, - "name": "Реле помпы септика", - "description": "Управляет помпой, должно периодически включаться и выключаться", - "connection_state": "active", // active | lost - "last_contact": "2025-07-28 18:35" + "id": 12, + "alias": "...", + "state": "active", // active | freeze + "device": { + "device_name": "Relay 1", + "device_type": "relay", + "firmware_version": "1.0.3", + "device_id": "ecf0a1b5c9d74f9a8e294c1f67b0a8b9", + "device_ip": "192.168.1.13" + }, + "name": "Реле помпы септика", + "description": "Управляет помпой, должно периодически включаться и выключаться", + "connection_state": "active", // active | lost + "last_contact": "2025-07-28 18:35", + "create_at": "2025-07-28 15:35" + } } } ``` @@ -129,25 +134,66 @@ ### Пример НЕ успешного ответа ```json { - "status": "error", - "message": "Device not exists" // "Permission error" + "status": false, + "error_alias": "...", + "msg": "..." } ``` --- -### GET `/api/v1/devices/alias/{{alias}}/status` OR GET `/api/v1/devices/id/{{id}}/status` +### GET `/api/v1/devices/id/{{id}}` +Получить информацию по отдельному девайсу + +### Пример ответа +```json + { + "status": true, + "data": { + "device": { + "id": 12, + "alias": "...", + "device_type": "relay", + "device_hard_id": "...", + "device_mac": "...", + "device_ip": "...", + "firmware_version": "...", + "name": "Реле помпы септика", + "state": "active", // active | freeze + "description": "Управляет помпой, должно периодически включаться и выключаться", + "connection_state": "active", // active | lost + "last_contact": "2025-07-28 18:35", + "create_at": "2025-07-28 15:35" + } + } + } + ``` + +### Пример НЕ успешного ответа +```json + { + "status": false, + "error_alias": "...", + "msg": "..." + } + ``` + +--- + +### GET `/api/v1/devices/id/{{id}}/status` Получить отдельный девайс ### Пример ответа ```json { - "status": "ok", - "device": { - "id": 12, - "alias": "...", - "device_status": { - // ... + "status": true, + "data": { + "device": { + "id": 12, + "alias": "...", + "device_response": { + // ... + } } } } @@ -155,12 +201,13 @@ --- -### POST `/api/v1/devices/id/{{id}}/action` OR POST `/api/v1/devices/alias/{{alias}}/action` +### POST `/api/v1/devices/action` Выполнить действие для отдельного девайса ### Пример запроса ```json { + "device_id": 47, "action": "action_name", "params": { // ... @@ -172,11 +219,11 @@ В ответе вернётся непосредственно ответ от устройства ```json { - "status": "ok", + "status": true, "device": { "id": 12, "alias": "alias_name_like_variable", - "response": { + "device_response": { // ... } } @@ -186,32 +233,46 @@ ### Пример НЕ успешного ответа ```json { - "status": "error", - "message": "Device does not support this action or params" // "Permission error" + "status": false, + "error_alias": "...", + "msg": "Device does not support this action or params", + "device_status": "error", + "device_error": "...", + "device_msg": "..." } ``` --- -### GET `/api/v1/devices/id/{{id}}/forget` OR GET `/api/v1/devices/alias/{{alias}}/forget` +### GET `/api/v1/devices/id/{{id}}/remove` Забыть выбраный девайс. Сам девайс при этом будет ресетнуть. **Доступно лишь супер админу.** ### Пример успешного ответа ```json { - "status": "ok" + "status": true + } + ``` + +### Пример НЕ успешного ответа +```json + { + "status": false, + "error_alias": "...", + "device_msg": "...", + "msg": "..." } ``` --- -### GET `/api/v1/devices/id/{{id}}/reboot` OR GET `/api/v1/devices/alias/{{alias}}/reboot` +### GET `/api/v1/devices/id/{{id}}/reboot` Принудительно перезагрузить устройство. **Доступно лишь админу** #### Пример успешного ответа ```json { - "status": "ok" + "status": true } ``` diff --git a/server/SHServ/Controllers/DevicesRESTAPIController.php b/server/SHServ/Controllers/DevicesRESTAPIController.php index 75c4f3d..7861d45 100644 --- a/server/SHServ/Controllers/DevicesRESTAPIController.php +++ b/server/SHServ/Controllers/DevicesRESTAPIController.php @@ -24,13 +24,24 @@ ]); } - public function setup_new_device($device_ip, $alias, $description) { + public function setup_new_device($device_ip, $alias, $name, $description) { $devices_model = new \SHServ\Models\Devices(); - $result = $devices_model -> connect_new_device($device_ip, $alias, $description); + $result = $devices_model -> connect_new_device($device_ip, $alias, $name, $description); - return $this -> utils() -> response_success([ - "result" => $result ? true : false - ]); + if($result and $result instanceof \SHServ\Entities\Device) { + $device_about = $result -> device_api() -> get_about(); + return $this -> utils() -> response_success([ + "device" => [ + "id" => $result -> id(), + "alias" => $result -> alias, + "name" => $result -> name, + "description" => $result -> description, + "device" => $device_about["data"] + ] + ]); + } + + return $this -> utils() -> response_error($result["err_alias"]); } public function remove_device($device_id) { @@ -59,13 +70,106 @@ return $this -> utils() -> response_error( $result["err_alias"], [], - [ "device_msg" => $result["device_msg"] ] + [ "device_msg" => $result["msg"] ?? "" ] ); } return $this -> utils() -> response_success([ - "result" => $result["result"] ? true : false, - "device_msg" => $result["device_msg"] + "device_msg" => $result["msg"] ]); } + + public function device_info($device_id) { + $device_id = intval($device_id); + $devices_model = new Devices(); + $result = $devices_model -> get_device_info($device_id); + + if(!$result) { + return $this -> utils() -> response_error("device_not_found"); + } + + return $this -> utils() -> response_success([ "device" => $result ]); + } + + public function device($device_id) { + $devices_model = new Devices(); + $device = $devices_model -> by_id(intval($device_id)); + + if(!$device) { + return $this -> utils() -> response_error("device_not_found"); + } + + $info = [ + "id" => $device -> id(), + "alias" => $device -> alias, + "device_type" => $device -> device_type, + "device_hard_id" => $device -> device_hard_id, + "device_mac" => $device -> device_mac, + "device_ip" => $device -> device_ip, + "firmware_version" => $device -> firmware_version, + "name" => $device -> name, + "description" => $device -> description, + "state" => $device -> state, + "connection_state" => $device -> connection_state, + "last_contact" => $device -> last_contact, + "create_at" => $device -> create_at + ]; + + return $this -> utils() -> response_success([ "device" => $info ]); + } + + public function device_status($device_id) { + $devices_model = new Devices(); + $device = $devices_model -> by_id(intval($device_id)); + + if(!$device) { + return $this -> utils() -> response_error("device_not_found"); + } + + $device_status = $device -> device_api() -> get_status(); + + if(!$device_status) { + return $this -> utils() -> response_error("device_request_fail"); + } + + $response_data = [ + "id" => $device -> id(), + "alias" => $device -> alias, + "device_response" => $device_status + ]; + + return $this -> utils() -> response_success(["device" => $response_data]); + } + + public function do_device_action($device_id, $action, $params) { + $devices_model = new Devices(); + $device = $devices_model -> by_id(intval($device_id)); + + if(!$device) { + return $this -> utils() -> response_error("device_not_found"); + } + + $result = $device -> device_api() -> post_action($action, $params); + $device_response = $result["data"] ?? []; + + if(!$device_response) { + return $this -> utils() -> response_error("device_request_fail"); + } + + if($device_response["status"] != "ok") { + return $this -> utils() -> response_error("device_request_fail", [], [ + "device_status" => $device_response["status"], + "device_error" => $device_response["status"] ?? "", + "device_msg" => $device_response["message"] ?? "" + ]); + } + + $response_data = [ + "id" => $device -> id(), + "alias" => $device -> alias, + "device_response" => $device_response + ]; + + return $this -> utils() -> response_success(["device" => $response_data]); + } } \ No newline at end of file diff --git a/server/SHServ/Entities/Device.php b/server/SHServ/Entities/Device.php index 368f8f6..dfa9abe 100644 --- a/server/SHServ/Entities/Device.php +++ b/server/SHServ/Entities/Device.php @@ -11,7 +11,7 @@ class Device extends \SHServ\Middleware\Entity { public static $table_name = "devices"; protected static $fields = [ - "id", "area_id", "alias", "name", "device_type", "device_name", "device_ip", + "id", "area_id", "alias", "name", "device_type", "device_ip", "device_mac", "device_hard_id", "firmware_version", "connection_state", "state", "description", "last_contact", "create_at", "update_at" ]; diff --git a/server/SHServ/Entities/DeviceAuth.php b/server/SHServ/Entities/DeviceAuth.php index 708b0e7..4c7b14a 100644 --- a/server/SHServ/Entities/DeviceAuth.php +++ b/server/SHServ/Entities/DeviceAuth.php @@ -5,7 +5,7 @@ class DeviceAuth extends \SHServ\Middleware\Entity { public static $table_name = "device_auth"; protected static $fields = [ - "id", "device_id", "device_token", "server_token", "state", "create_at" + "id", "device_id", "device_token", "state", "create_at" ]; public function __construct(Int $id, Array $data = []){ diff --git a/server/SHServ/Models/Devices.php b/server/SHServ/Models/Devices.php index 8877853..e6390b5 100644 --- a/server/SHServ/Models/Devices.php +++ b/server/SHServ/Models/Devices.php @@ -8,17 +8,23 @@ use \SHServ\Entities\DeviceAuth; class Devices extends \SHServ\Middleware\Model { - public function connect_new_device(String $device_ip, String $alias = "", String $name = ""): Device | null { + public function connect_new_device(String $device_ip, String $alias = "", String $name = "", String $description = ""): Device | Array { // validate device $device_api = new Base($device_ip); $device_info = $device_api -> get_about(); if(!$device_info["data"]) { - return null; + return [ + "result" => false, + "err_alias" => "device_not_found" + ]; } if($device_info["data"]["status"] != "setup") { - return null; + return [ + "result" => false, + "err_alias" => "device_mode_error" + ]; } // create in table devices @@ -27,14 +33,13 @@ "alias" => $alias, "name" => $name, "device_type" => $device_info["data"]["device_type"], - "device_name" => $device_info["data"]["device_name"], "device_ip" => $device_info["data"]["ip_address"], "device_mac" => $device_info["data"]["mac_address"], "device_hard_id" => $device_info["data"]["device_id"], "firmware_version" => $device_info["data"]["firmware_version"], "connection_state" => "active", "state" => "active", - "description" => "", + "description" => $description, "last_contact" => date("Y-m-d H:i:s"), "create_at" => date("Y-m-d H:i:s") ]); @@ -42,7 +47,10 @@ $device = $device_id ? new Device($device_id) : null; if(!$device) { - return null; + return [ + "result" => false, + "err_alias" => "db_error" + ]; } // generate token @@ -54,16 +62,21 @@ $device_auth = app() -> thin_builder -> insert(DeviceAuth::$table_name, [ "device_id" => $device -> id(), "device_token" => $device_token, - "server_token" => "", "state" => "active", "create_at" => date("Y-m-d H:i:s") ]); if(!$device_auth) { - return null; + app() -> thin_builder -> delete(Device::$table_name, [ "id", "=", $device -> id() ]); + + return [ + "result" => false, + "err_alias" => "device_error_of_auth" + ]; } $device -> set_device_token($device_token); + $device -> device_api() -> set_device_name($name); return $device; } @@ -244,4 +257,31 @@ "msg" => "{$err_type}. {$err_msg}" ]; } + + public function get_device_info($device_id_or_alias): Array | null { + if(is_string($device_id_or_alias)) { + $device = $this -> by_alias($device_id_or_alias); + } else { + $device = $this -> by_id($device_id_or_alias); + } + + if(!$device) { + return null; + } + + $about = $device -> device_api() -> get_about(); + $info = [ + "id" => $device -> id(), + "alias" => $device -> alias, + "name" => $device -> name, + "description" => $device -> description, + "state" => $device -> state, + "connection_state" => $device -> connection_state, + "last_contact" => $device -> last_contact, + "create_at" => $device -> create_at, + "device" => $about["data"] ?? [] + ]; + + return $info; + } } \ No newline at end of file diff --git a/server/SHServ/Routes/RESTAPI_v1.php b/server/SHServ/Routes/RESTAPI_v1.php index b362bdb..8dafade 100644 --- a/server/SHServ/Routes/RESTAPI_v1.php +++ b/server/SHServ/Routes/RESTAPI_v1.php @@ -6,27 +6,29 @@ protected function restapi_uri_routes() { $this -> router -> uri("/api/v1/devices/scanning/setup", "{$this -> cn}\\DevicesRESTAPIController@scanning__ready_to_setup"); $this -> router -> uri("/api/v1/devices/scanning/all", "{$this -> cn}\\DevicesRESTAPIController@scanning__all"); - } - protected function restapi_get_routes() { - $this -> router -> get( - [ "device_id" ], - "{$this -> cn}\\DevicesRESTAPIController@remove_device", - '/api/v1/devices/remove' - ); - - $this -> router -> get( - [ "device_id" ], - "{$this -> cn}\\DevicesRESTAPIController@reboot_device", - '/api/v1/devices/reboot' - ); + $this -> router -> uri('/api/v1/devices/id/$device_id/reboot', "{$this -> cn}\\DevicesRESTAPIController@reboot_device"); + $this -> router -> uri('/api/v1/devices/id/$device_id/remove', "{$this -> cn}\\DevicesRESTAPIController@remove_device"); + $this -> router -> uri('/api/v1/devices/id/$device_id/info', "{$this -> cn}\\DevicesRESTAPIController@device_info"); + $this -> router -> uri('/api/v1/devices/id/$device_id', "{$this -> cn}\\DevicesRESTAPIController@device"); + $this -> router -> uri('/api/v1/devices/id/$device_id/status', "{$this -> cn}\\DevicesRESTAPIController@device_status"); } protected function restapi_post_routes() { $this -> router -> post( - [ "device_ip", "alias", "description"], + [ "device_ip", "alias", "name", "description" ], "{$this -> cn}\\DevicesRESTAPIController@setup_new_device", "/api/v1/devices/setup/new-device" ); + + $this -> router -> post( + [ "device_id", "action", "params" ], + "{$this -> cn}\\DevicesRESTAPIController@do_device_action", + "/api/v1/devices/action" + ); + } + + protected function restapi_get_routes() { + } } \ No newline at end of file diff --git a/server/SHServ/Utils.php b/server/SHServ/Utils.php index f9a117f..e81b7dd 100644 --- a/server/SHServ/Utils.php +++ b/server/SHServ/Utils.php @@ -29,6 +29,10 @@ ]); } + public function get_msg_by_alias(String $alias){ + return FCONF['text_msgs'][$alias]; + } + public function compress_image(String $source, String $destination, Int $quality) { $info = getimagesize($source); diff --git a/server/SHServ/text-msgs.php b/server/SHServ/text-msgs.php index 39413a3..5f527e9 100644 --- a/server/SHServ/text-msgs.php +++ b/server/SHServ/text-msgs.php @@ -31,6 +31,9 @@ "unknown_device" => "", "error_of_device_auth" => "", "device_request_fail" => "", + "device_mode_error" => "", + "db_error" => "", + "device_error_of_auth" => "", // Other "accept_removing" => "Подтвердите удаление",