From f5bb7921bb5c8668f70d3e83334733b34a948e49 Mon Sep 17 00:00:00 2001 From: Alex Solomaha Date: Mon, 27 Feb 2017 23:22:48 +0200 Subject: [PATCH] RGB Widget frontend --- assets/MDThemeAsset.php | 1 + config/params.php | 9 + helpers/RGBHelper.php | 24 + models/Item.php | 50 +- modules/api/controllers/ItemController.php | 2 +- servers/CoreServer.php | 661 +++++++++++---------- views/panel/_rgb.php | 2 +- views/panel/_variable.php | 2 +- views/panel/index.php | 104 +++- views/site/index.php | 3 - web/css/md.theme.css | 40 +- web/css/panel.css | 2 - web/css/theme.css | 132 ---- web/js/panel.js | 385 +++++++----- 14 files changed, 740 insertions(+), 677 deletions(-) create mode 100644 helpers/RGBHelper.php diff --git a/assets/MDThemeAsset.php b/assets/MDThemeAsset.php index 09956a8..1b6968c 100644 --- a/assets/MDThemeAsset.php +++ b/assets/MDThemeAsset.php @@ -21,5 +21,6 @@ class MDThemeAsset extends AssetBundle 'yii\web\JqueryAsset', 'yii\bootstrap\BootstrapPluginAsset', 'app\assets\SnackbarjsAsset', + 'app\assets\SpectrumAsset', ]; } diff --git a/config/params.php b/config/params.php index 922ea74..d39a5b0 100644 --- a/config/params.php +++ b/config/params.php @@ -12,6 +12,15 @@ $params = [ 'connectionCheckTimeout' => 180, 'connectionCheckMaxIteration' => 2, ], + 'items' => [ + 'rgb' => [ + 'fade-time' => 10000, + 'color-time' => 5000, + 'red' => 0, + 'green' => 150, + 'blue' => 150, + ], + ], 'telegramBotApiKey' => '', 'telegramBotChatId' => '', ]; diff --git a/helpers/RGBHelper.php b/helpers/RGBHelper.php new file mode 100644 index 0000000..2ad6e00 --- /dev/null +++ b/helpers/RGBHelper.php @@ -0,0 +1,24 @@ +default_value)) { - return $this->default_value; - } - switch ($this->type) { - case Item::TYPE_SWITCH: - case Item::TYPE_VARIABLE_BOOLEAN: - case Item::TYPE_VARIABLE_BOOLEAN_DOOR: - return false; - - case Item::TYPE_VARIABLE_TEMPERATURE: - case Item::TYPE_VARIABLE_HUMIDITY: - return 0; - - case Item::TYPE_RGB: + case self::TYPE_RGB: return [ - 0, - 0, - 0, + 'mode' => 'static', + 'red' => 0, + 'green' => 0, + 'blue' => 0, + 'fade_time' => Yii::$app->params['items']['rgb']['fade-time'], ]; + default: + return 'N/A'; } - - return false; } } diff --git a/modules/api/controllers/ItemController.php b/modules/api/controllers/ItemController.php index 983ca86..a70f9ed 100644 --- a/modules/api/controllers/ItemController.php +++ b/modules/api/controllers/ItemController.php @@ -189,7 +189,7 @@ class ItemController extends Controller throw new BadRequestHttpException('This item is not the RGB one'); } - if (!in_array($mode, Item::getModesArray())) { + if (!in_array($mode, Item::getRGBModesArray())) { throw new InvalidParamException('Unknown mode'); } diff --git a/servers/CoreServer.php b/servers/CoreServer.php index 1f1361f..0211730 100644 --- a/servers/CoreServer.php +++ b/servers/CoreServer.php @@ -3,6 +3,7 @@ namespace app\servers; use app\helpers\IPHelper; +use app\helpers\RGBHelper; use app\models\Board; use app\models\Event; use app\models\Setting; @@ -11,15 +12,18 @@ use app\models\Trigger; use app\models\History; use app\models\Item; use app\models\User; -use MongoDB\Driver\Exception\AuthenticationException; +use Guzzle\Http\QueryString; use Ratchet\ConnectionInterface; use Ratchet\MessageComponentInterface; +use Ratchet\WebSocket\Version\RFC6455\Connection; use React\EventLoop\LoopInterface; use React\EventLoop\Timer\TimerInterface; use Yii; use yii\base\InvalidParamException; use yii\base\NotSupportedException; +use yii\helpers\ArrayHelper; use yii\helpers\Json; +use yii\web\BadRequestHttpException; use yii\web\ForbiddenHttpException; use yii\web\NotFoundHttpException; use yii\web\UnauthorizedHttpException; @@ -40,13 +44,13 @@ class CoreServer implements MessageComponentInterface * All connected users * @var ConnectionInterface[] */ - protected $user_clients; + protected $userConnections; /** * All connected boards * @var ConnectionInterface[] */ - protected $board_clients; + protected $boardConnections; /** * Format like this: @@ -55,19 +59,19 @@ class CoreServer implements MessageComponentInterface * * @var array */ - protected $item_values; + protected $itemValues; /** * `item_id` => TimerInterface * @var TimerInterface[] */ - protected $connectionCheckTimers; + protected $pingTimers; /** * `item_id` => iteration count * @var array */ - protected $connectionCheckIteration; + protected $pingCount; /** * @var TimerInterface[] @@ -85,11 +89,11 @@ class CoreServer implements MessageComponentInterface { // Init variables $this->loop = $loop; - $this->user_clients = []; - $this->board_clients = []; - $this->item_values = []; - $this->connectionCheckTimers = []; - $this->connectionCheckIteration = []; + $this->userConnections = []; + $this->boardConnections = []; + $this->itemValues = []; + $this->pingTimers = []; + $this->pingCount = []; $this->triggerTimers = []; // Database driver hack: Prevent MySQL for disconnecting by timeout @@ -98,168 +102,40 @@ class CoreServer implements MessageComponentInterface Yii::$app->db->createCommand('SHOW TABLES;')->execute(); }); - $this->updateItems(); - + // Do the startup tasks +// $this->updateItems(); $this->scheduleTriggers(); $this->log('Server started'); } + /** + * @inheritdoc + */ public function onOpen(ConnectionInterface $conn) { - $this->log('Managing new connection...'); + /** @var Connection $conn */ + /** @var QueryString $query */ $query = $conn->WebSocket->request->getQuery(); $type = $query->get('type'); switch ($type) { case 'user': - $this->log('Connection type is User. Authenticating...'); - - $userID = $query->get('id'); - $userAuthToken = $query->get('auth_token'); - - if (!$userID or !$userAuthToken) { - $this->log("Invalid credentials: '$userID', '$userAuthToken'"); - - throw new InvalidParamException("Required fields does not exist"); - } - - $user = User::findOne([ - 'id' => $userID, - ]); - - if (!$user) { - $this->log("User was not found with id '$userID'"); - - throw new NotFoundHttpException("User was not found with id '$userID'"); - } - - if ($user->getAuthToken() != $userAuthToken) { - $this->log("User [$user->id] wrong auth token ($userAuthToken and {$user->getAuthToken()})"); - - throw new AuthenticationException("Wrong credentials"); - } - - // API request - $api = false; - - if ($conn->remoteAddress == '127.0.0.1' and $conn->WebSocket->request->getHeader('Origin') == 'origin') { - $api = true; - } - - // Close previous connection if it is not an API connection - if (isset($this->user_clients[$user->id]) and !$api) { - $this->user_clients[$user->id]->close(); - } - - // Regenerate auth key - $user->reGenerateAuthToken(); - - // Attach to users - $conn->User = $user; - $conn->api = $api; - $this->user_clients[$user->id] = $conn; - - // Prepare Items for User - $items = Item::find() - ->active() - ->select(['id', 'type', 'room_id', 'board_id', 'default_value']) - ->asArray() - ->all(); - - for ($i = 0; $i < count($items); $i++) { - $items[$i]['value'] = $this->getItemSavedValue($items[$i]['id'], $items[$i]['default_value']); - } - - $conn->send(Json::encode([ - 'type' => 'init', - 'items' => $items, - ])); - - $this->logUserConnection($user, true); - - return $this->log("Connected user [{$user->id}] {$user->username}"); + $this->handleUserConnection($conn, $query); + break; case 'board': - $this->log('Connection type is Board. Authenticating...'); - - $boardID = $query->get('id'); - $boardSecret = $query->get('secret'); - - if (!$boardID or !$boardSecret) { - $this->log("Wrong login data: '$boardID' and '$boardSecret'"); - - throw new UnauthorizedHttpException('Wrong credentials'); - } - - $board = Board::findOne([ - 'id' => $boardID, - 'type' => Board::TYPE_WEBSOCKET, - 'secret' => $boardSecret, - ]); - - if (!$board) { - $this->log("Board [$boardID] not found!"); - - throw new NotFoundHttpException("Board with given ID does not exists"); - } - - if (!$board->remote_connection and !IPHelper::isLocal($conn->remoteAddress)) { - $this->log("Remote connection blocked for board [$boardID]; IP: {$conn->remoteAddress}"); - - throw new ForbiddenHttpException("Remote connection is not allowed for this Board"); - } - - // Attach to boards - $conn->Board = $board; - $this->board_clients[$board->id] = $conn; - - // Reset previous timer and start a new one - $this->startConnectionCheckTimer($boardID, true); - - // Set default values to board's items - foreach ($board->items as $item) { - if ($item->default_value and !is_null($item->default_value)) { - switch ($item->type) { - case Item::TYPE_SWITCH: - $this->sendToBoard($board->id, [ - 'type' => $item->default_value == 1 ? 'turnON' : 'turnOFF', - 'pin' => $item->pin, - ]); - - break; - case Item::TYPE_RGB: - $rgbData = $this->valueToRgbData($item->default_value); - - $red = $rgbData[0]; - $green = $rgbData[1]; - $blue = $rgbData[2]; - $fade = (bool)$rgbData[3]; - - $this->sendToBoard($board->id, [ - 'type' => 'rgb', - 'red' => $red * 4, - 'green' => $green * 4, - 'blue' => $blue * 4, - 'fade' => $fade, - ]); - - break; - } - } - } - - $this->triggerBoardConnection($board, true); - - $this->logBoardConnection($board->id, true); - - return $this->log("Connected board [{$board->id}]"); + $this->handleBoardConnection($conn, $query); + break; + default: + throw new BadRequestHttpException('Unknown device type'); } - - return $this->log('Connection has unknown type. Disconnect'); } + /** + * @inheritdoc + */ public function onMessage(ConnectionInterface $from, $msg) { if (isset($from->User)) { @@ -275,6 +151,9 @@ class CoreServer implements MessageComponentInterface return $this->log("Message: '$msg' from unknown client"); } + /** + * @inheritdoc + */ public function onClose(ConnectionInterface $conn) { if (isset($conn->User)) { @@ -284,12 +163,10 @@ class CoreServer implements MessageComponentInterface } elseif (isset($conn->Board)) { $boardId = $conn->Board->id; - $this->log("Disconnecting Board [{$boardId}]..."); - // Cancel connection check timer - $this->stopConnectionCheckTimer($boardId); + $this->stopPingTimer($boardId); - unset($this->board_clients[$boardId]); + unset($this->boardConnections[$boardId]); $this->triggerBoardConnection($conn->Board, false); @@ -299,6 +176,9 @@ class CoreServer implements MessageComponentInterface } } + /** + * @inheritdoc + */ public function onError(ConnectionInterface $conn, \Exception $e) { $this->log("Error: {$e->getMessage()} in file {$e->getFile()} at line {$e->getLine()}"); @@ -307,6 +187,160 @@ class CoreServer implements MessageComponentInterface $conn->close(); } + /** + * @param Connection $conn + * @param QueryString $query + * @throws UnauthorizedHttpException + */ + protected function handleUserConnection($conn, $query) + { + $userID = $query->get('id'); + $userAuthToken = $query->get('auth_token'); + + $user = User::findOne([ + 'id' => $userID, + 'auth_token' => $userAuthToken, + ]); + + if (!$user) { + $this->log("Wrong credentials: '$userID', '$userAuthToken''"); + + throw new UnauthorizedHttpException("Wrong credentials"); + } + + // Check if it is an API request + $api = $conn->remoteAddress == '127.0.0.1' and $conn->WebSocket->request->getHeader('Origin') == 'origin'; + + // Close previous connection if it is not an API connection + if (isset($this->userConnections[$user->id]) and !$api) { + $this->userConnections[$user->id]->close(); + } + + // Regenerate auth token + $user->reGenerateAuthToken(); + + // Attach to users + $conn->User = $user; + $conn->api = $api; + + $this->userConnections[$user->id] = $conn; + + // Prepare Items for User + $itemModels = Item::find() + ->active() + ->all(); + + $items = []; + + foreach ($itemModels as $itemModel) { + $itemData = []; + $itemData['id'] = $itemModel->id; + $itemData['type'] = $itemModel->type; + $itemData['room_id'] = $itemModel->room_id; + $itemData['board_id'] = $itemModel->board_id; + $itemData['pin'] = $itemModel->pin; + $itemData['name'] = $itemModel->name; + $itemData['icon'] = $itemModel->icon; + $itemData['bg'] = $itemModel->bg; + $itemData['class'] = $itemModel->class; + $itemData['sort_order'] = $itemModel->sort_order; + + $itemData['value'] = $this->getItemSavedValue($itemModel->id, $itemModel->getDefaultNAValue()); + + $items[$itemModel->id] = $itemData; + } + + $conn->send(Json::encode([ + 'type' => 'init', + 'items' => $items, + ])); + + $this->logUserConnection($user, true); + + $this->log("Connected user [{$user->id}] {$user->username}"); + } + + /** + * @param ConnectionInterface $conn + * @param QueryString $query + * @throws ForbiddenHttpException + * @throws NotFoundHttpException + * @throws UnauthorizedHttpException + */ + protected function handleBoardConnection(ConnectionInterface $conn, $query) + { + $boardID = $query->get('id'); + $boardSecret = $query->get('secret'); + + if (!$boardID or !$boardSecret) { + $this->log("Wrong board login data: '$boardID' and '$boardSecret'"); + + throw new UnauthorizedHttpException('Wrong credentials'); + } + + $board = Board::findOne([ + 'id' => $boardID, + 'type' => Board::TYPE_WEBSOCKET, + 'secret' => $boardSecret, + ]); + + if (!$board) { + $this->log("Board [$boardID] not found!"); + + throw new NotFoundHttpException("Board with given ID does not exists"); + } + + if (!$board->remote_connection and !IPHelper::isLocal($conn->remoteAddress)) { + $this->log("Remote connection blocked for board [$boardID]; IP: {$conn->remoteAddress}"); + + throw new ForbiddenHttpException("Remote connection is not allowed for this Board"); + } + + // Attach to boards + $conn->Board = $board; + $this->boardConnections[$board->id] = $conn; + + // Reset previous timer and start a new one + $this->startPingTimer($boardID, true); + + // Set default values to board's items +// foreach ($board->items as $item) { +// if ($item->default_value and !is_null($item->default_value)) { +// switch ($item->type) { +// case Item::TYPE_SWITCH: +// $this->sendToBoard($board->id, [ +// 'type' => $item->default_value == 1 ? 'turnON' : 'turnOFF', +// 'pin' => $item->pin, +// ]); +// +// break; +// case Item::TYPE_RGB: +// $rgbData = $this->valueToRgbData($item->default_value); +// +// $red = $rgbData[0]; +// $green = $rgbData[1]; +// $blue = $rgbData[2]; +// $fade = (bool)$rgbData[3]; +// +// $this->sendToBoard($board->id, [ +// 'type' => 'rgb', +// 'red' => $red * 4, +// 'green' => $green * 4, +// 'blue' => $blue * 4, +// 'fade' => $fade, +// ]); +// +// break; +// } +// } +// } + + $this->triggerBoardConnection($board, true); + $this->logBoardConnection($board->id, true); + + $this->log("Connected board [{$board->id}]"); + } + /** * @param $from * @param $msg @@ -328,8 +362,6 @@ class CoreServer implements MessageComponentInterface return $this->handleTurnOff($from, $user, $data); case 'rgb': return $this->handleRgb($from, $user, $data); - case 'rgbMode': - return $this->handleRgbMode($from, $user, $data); case 'schedule-triggers': return $this->scheduleTriggers(); case 'update-items': @@ -345,6 +377,7 @@ class CoreServer implements MessageComponentInterface * @param $from * @param $msg * @return bool + * @throws NotFoundHttpException */ public function handleBoardMessage($from, $msg) { @@ -352,8 +385,8 @@ class CoreServer implements MessageComponentInterface $board = $from->Board; $data = Json::decode($msg); - // Board responds: restart connection check timer - $this->startConnectionCheckTimer($board->id); + // Restart ping timer + $this->startPingTimer($board->id); switch ($data['type']) { case 'value': @@ -385,42 +418,67 @@ class CoreServer implements MessageComponentInterface $this->logItemValue($item, $value); break; - case 'rgbMode': - /** - * Message structure: - * {"start":true,"type":"rgbMode","mode":"rainbow","pin":1} - */ - $value = $data['mode']; - $pin = (integer)$data['pin']; - $start = (bool)$data['start']; + case 'rgb': + $itemId = (integer)$data['item_id']; + $mode = $data['mode']; + $fadeTime = (int)$data['fade_time']; $item = Item::findOne([ + 'id' => $itemId, 'board_id' => $board->id, - 'pin' => $pin, ]); if (!$item) { - return $this->log('Trying to use unknown item'); + $this->log("Board [{$board->id}] tried to use unknown item"); + throw new NotFoundHttpException('Item does not exist'); } - if ($start) { - $value = $this->saveItemValue($item->id, $value, $item->type, false); - } else { - $value = $this->saveItemValue($item->id, $item->getDefaultValue(), $item->type); + if (!in_array($mode, Item::getRGBModesArray())) { + $this->log("Board [{$board->id}] tried to use unknown RGB mode"); + throw new InvalidParamException('Unknown RGB mode'); } - // TODO: trigger + if ($fadeTime < 0) { + $fadeTime = 0; + } - $this->sendUsers([ - 'type' => 'value', + $commonParameters = [ + 'type' => 'rgb', 'item_id' => $item->id, - 'item_type' => $item->type, - 'value' => $value, - 'start' => $start, - ]); + 'mode' => $mode, + 'fade_time' => $fadeTime, + ]; - // Save to history - $this->logItemValue($item, $start ? 'start:' : '' . $value); + $modeParameters = []; + + if ($mode === Item::RGB_MODE_STATIC or $mode === Item::RGB_MODE_FADE) { + // Fill saved values if not provided + $red = isset($data['red']) ? $data['red'] : Yii::$app->params['items']['rgb']['red']; + $green = isset($data['green']) ? $data['green'] : Yii::$app->params['items']['rgb']['green']; + $blue = isset($data['blue']) ? $data['blue'] : Yii::$app->params['items']['rgb']['blue']; + + // Convert color from 1023 to 255 + $red = RGBHelper::from10to8($red); + $green = RGBHelper::from10to8($green); + $blue = RGBHelper::from10to8($blue); + + $modeParameters['red'] = $red; + $modeParameters['green'] = $green; + $modeParameters['blue'] = $blue; + } + + if ($mode === Item::RGB_MODE_WAVE or $mode === Item::RGB_MODE_FADE) { + $colorTime = isset($data['color_time']) ? $data['color_time'] : Yii::$app->params['items']['rgb']['color-time']; + + $modeParameters['color_time'] = $colorTime; + } + + $parameters = ArrayHelper::merge($commonParameters, $modeParameters); + + $this->sendUsers($parameters); + + $this->logItemValue($item, serialize($parameters)); + $this->saveItemValue($item->id, $parameters, $item->type); break; case 'values': @@ -600,108 +658,66 @@ class CoreServer implements MessageComponentInterface ]); } - $red = $data['red']; - $green = $data['green']; - $blue = $data['blue']; - - if ($red > 255) { - $red = 255; - } - - if ($green > 255) { - $green = 255; - } - - if ($blue > 255) { - $blue = 255; - } - - $board = $item->board; - - switch ($board->type) { - case Board::TYPE_AREST: - throw new NotSupportedException(); - - case Board::TYPE_WEBSOCKET: - if (!$this->isBoardConnected($board->id)) { - return $from->send(Json::encode([ - 'type' => 'error', - 'message' => 'Устройство не подключено', - ])); - } - - $fade = isset($data['fade']) ? (bool)$data['fade'] : false; - - $this->sendToBoard($board->id, [ - 'type' => 'rgb', - 'red' => $red * 4, - 'green' => $green * 4, - 'blue' => $blue * 4, - 'fade' => $fade, - ]); - - break; - } - -// $rgbArray = [ -// $red, -// $green, -// $blue -// ]; - -// $this->item_values[$item->id]['value'] = $rgbArray; - - $history = new History(); - $history->type = History::TYPE_USER_ACTION; - $history->user_id = $user->id; - $history->item_id = $item->id; - $history->commited_at = time(); - $history->value = $red . ',' . $green . ',' . $blue; - - if (!$history->save()) { - $this->log("Cannot log: "); - var_dump($history->errors); - } - - return true; - } - - /** - * @param ConnectionInterface $from - * @param User $user - * @param array $data - * @return bool|mixed - * @throws NotSupportedException - */ - protected function handleRgbMode($from, $user, $data) - { - $item_id = (int)$data['item_id']; - $item = Item::findOne($item_id); - - if (!$item) { - return $from->send(Json::encode([ - 'type' => 'error', - 'message' => 'Такое устройство не существует', - ])); - } - - if ($item->type !== Item::TYPE_RGB) { - return $from->send(Json::encode([ - 'type' => 'error', - 'message' => 'Данный тип устройства не является RGB', - ])); - } - $mode = $data['mode']; - $start = (bool)$data['start']; + $fadeTime = isset($data['fade_time']) ? $data['fade_time'] : Yii::$app->params['items']['rgb']['fade-time']; - if (!in_array($mode, Item::getModesArray())) { - return $from->send(Json::encode([ - 'type' => 'error', - 'message' => 'Неизвестный режим', - ])); + if (!in_array($mode, Item::getRGBModesArray())) { + throw new InvalidParamException('Unknown RGB mode'); } + if ($fadeTime < 0) { + $fadeTime = 0; + } + + $commonParameters = [ + 'type' => 'rgb', + 'item_id' => $item->id, + 'mode' => $mode, + 'fade_time' => $fadeTime, + ]; + + $modeParameters = []; + + if ($mode === Item::RGB_MODE_STATIC or $mode === Item::RGB_MODE_FADE) { + // Fill saved values if not provided + $red = isset($data['red']) ? $data['red'] : Yii::$app->params['items']['rgb']['red']; + $green = isset($data['green']) ? $data['green'] : Yii::$app->params['items']['rgb']['green']; + $blue = isset($data['blue']) ? $data['blue'] : Yii::$app->params['items']['rgb']['blue']; + + // Convert color from 255 to 1023 + if ($red > 255) { + $red = 255; + } + + if ($green > 255) { + $green = 255; + } + + if ($blue > 255) { + $blue = 255; + } + + $red = RGBHelper::from8to10($red); + $green = RGBHelper::from8to10($green); + $blue = RGBHelper::from8to10($blue); + + $modeParameters['red'] = $red; + $modeParameters['green'] = $green; + $modeParameters['blue'] = $blue; + } + + if ($mode === Item::RGB_MODE_WAVE or $mode === Item::RGB_MODE_FADE) { + $colorTime = isset($data['color_time']) ? $data['color_time'] : Yii::$app->params['items']['rgb']['color-time']; + + if ($colorTime < 0) { + $colorTime = 0; + } + + $modeParameters['color_time'] = $colorTime; + } + + $parameters = ArrayHelper::merge($commonParameters, $modeParameters); + $board = $item->board; switch ($board->type) { @@ -716,11 +732,7 @@ class CoreServer implements MessageComponentInterface ])); } - $this->sendToBoard($board->id, [ - 'type' => 'rgbMode', - 'mode' => $mode, - 'action' => $start ? 'start' : 'stop', - ]); + $this->sendToBoard($board->id, $parameters); break; } @@ -730,10 +742,10 @@ class CoreServer implements MessageComponentInterface $history->user_id = $user->id; $history->item_id = $item->id; $history->commited_at = time(); - $history->value = $mode . ', ' . $start ? 'start' : 'stop'; + $history->value = serialize($parameters); if (!$history->save()) { - $this->log("Cannot log: "); + $this->log("Cannot log:"); var_dump($history->errors); } @@ -792,7 +804,7 @@ class CoreServer implements MessageComponentInterface { $msg = Json::encode($data); - foreach ($this->user_clients as $client) { + foreach ($this->userConnections as $client) { $client->send($msg); } } @@ -802,24 +814,21 @@ class CoreServer implements MessageComponentInterface * * @param integer $board_id * @param array $data - * @return bool|ConnectionInterface */ protected function sendToBoard($board_id, $data) { - if (isset($this->board_clients[$board_id])) { + if (isset($this->boardConnections[$board_id])) { /** @var ConnectionInterface $client */ - $client = $this->board_clients[$board_id]; + $client = $this->boardConnections[$board_id]; $msg = Json::encode($data); $this->log("Sending to board [$board_id]: $msg"); - return $client->send($msg); + $client->send($msg); + } else { + $this->log("Cannot send to board [$board_id]: not connected"); } - - $this->log("Cannot send to board [$board_id]: not connected"); - - return false; } /** @@ -852,7 +861,7 @@ class CoreServer implements MessageComponentInterface */ protected function isBoardConnected($boardID) { - return isset($this->board_clients[$boardID]); + return isset($this->boardConnections[$boardID]); } /** @@ -973,7 +982,7 @@ class CoreServer implements MessageComponentInterface $this->log("Connection check for Board [$boardID]..."); // Check if it is already disconnected - if (!isset($this->board_clients[$boardID])) { + if (!isset($this->boardConnections[$boardID])) { $this->logBoardConnection($boardID, false); $this->log("Board [$boardID] has already been disconnected"); @@ -981,18 +990,18 @@ class CoreServer implements MessageComponentInterface return; } - if (isset($this->connectionCheckIteration[$boardID])) { - if ($this->connectionCheckIteration[$boardID] >= Yii::$app->params['server']['connectionCheckMaxIteration']) { + if (isset($this->pingCount[$boardID])) { + if ($this->pingCount[$boardID] >= Yii::$app->params['server']['connectionCheckMaxIteration']) { $this->log("Maximum ignored ping commands reached. Disconnecting..."); - $this->board_clients[$boardID]->close(); + $this->boardConnections[$boardID]->close(); return; } - $this->connectionCheckIteration[$boardID]++; + $this->pingCount[$boardID]++; } else { - $this->connectionCheckIteration[$boardID] = 1; + $this->pingCount[$boardID] = 1; } $this->sendToBoard($boardID, [ @@ -1356,30 +1365,35 @@ class CoreServer implements MessageComponentInterface } /** + * Checks if item value is stored and if so returns it. + * If value is missing - returns default from parameter + * * @param int $item_id * @param mixed $defaultValue * @return mixed */ - protected function getItemSavedValue($item_id, $defaultValue = false) + protected function getItemSavedValue($item_id, $defaultValue = null) { if ($this->hasItemSavedValue($item_id)) { - return $this->item_values[$item_id]; + return $this->itemValues[$item_id]; } return $defaultValue; } /** + * Checks if item value is stored. + * * @param int $item_id * @return bool */ protected function hasItemSavedValue($item_id) { - return isset($this->item_values[$item_id]); + return isset($this->itemValues[$item_id]) and $this->itemValues[$item_id] !== null; } /** - * Saves to value array and returns it. Normalization is on by default + * Saves to value array and returns it. Normalization is enabled by default * * @param int $item_id * @param mixed $value @@ -1393,7 +1407,7 @@ class CoreServer implements MessageComponentInterface $value = $this->normalizeItemValue($value, $item_type); } - $this->item_values[$item_id] = $value; + $this->itemValues[$item_id] = $value; return $value; } @@ -1414,9 +1428,6 @@ class CoreServer implements MessageComponentInterface case Item::TYPE_VARIABLE_TEMPERATURE: case Item::TYPE_VARIABLE_HUMIDITY: return (int)$value; - - case Item::TYPE_RGB: - return $this->valueToRgb($value); } return $value; @@ -1430,14 +1441,14 @@ class CoreServer implements MessageComponentInterface * @param int $boardID * @param bool $stopPrevious */ - protected function startConnectionCheckTimer($boardID, $stopPrevious = true) + protected function startPingTimer($boardID, $stopPrevious = true) { if ($stopPrevious) { - $this->stopConnectionCheckTimer($boardID); + $this->stopPingTimer($boardID); } // Start connection checks - $this->connectionCheckTimers[$boardID] = $this->loop->addPeriodicTimer( + $this->pingTimers[$boardID] = $this->loop->addPeriodicTimer( Yii::$app->params['server']['connectionCheckTimeout'], function () use ($boardID) { $this->doConnectionCheckTimer($boardID); @@ -1451,18 +1462,18 @@ class CoreServer implements MessageComponentInterface * @param int $boardID * @param bool $resetCount */ - protected function stopConnectionCheckTimer($boardID, $resetCount = true) + protected function stopPingTimer($boardID, $resetCount = true) { - if (isset($this->connectionCheckTimers[$boardID])) { - if ($this->connectionCheckTimers[$boardID] instanceof TimerInterface) { - $this->connectionCheckTimers[$boardID]->cancel(); + if (isset($this->pingTimers[$boardID])) { + if ($this->pingTimers[$boardID] instanceof TimerInterface) { + $this->pingTimers[$boardID]->cancel(); } - unset($this->connectionCheckTimers[$boardID]); + unset($this->pingTimers[$boardID]); } - if ($resetCount and isset($this->connectionCheckIteration[$boardID])) { - unset($this->connectionCheckIteration[$boardID]); + if ($resetCount and isset($this->pingCount[$boardID])) { + unset($this->pingCount[$boardID]); } } } diff --git a/views/panel/_rgb.php b/views/panel/_rgb.php index beee035..b1b6919 100644 --- a/views/panel/_rgb.php +++ b/views/panel/_rgb.php @@ -7,7 +7,7 @@ use rmrevin\yii\fontawesome\FA; ?> -
+
icon) ?> diff --git a/views/panel/_variable.php b/views/panel/_variable.php index 42f0b19..e9dd93f 100644 --- a/views/panel/_variable.php +++ b/views/panel/_variable.php @@ -14,6 +14,6 @@ use rmrevin\yii\fontawesome\FA;
icon) ?>
-
getDefaultValue() ?>
+
getDefaultNAValue() ?>
diff --git a/views/panel/index.php b/views/panel/index.php index af523dd..8a9b77e 100644 --- a/views/panel/index.php +++ b/views/panel/index.php @@ -72,27 +72,89 @@ $this->title = 'Панель Управления'; diff --git a/views/site/index.php b/views/site/index.php index 976ac51..bdc8c5b 100644 --- a/views/site/index.php +++ b/views/site/index.php @@ -4,6 +4,3 @@ $this->title = 'Главная'; ?> -
-

title ?>

-
diff --git a/web/css/md.theme.css b/web/css/md.theme.css index d996926..f480dca 100644 --- a/web/css/md.theme.css +++ b/web/css/md.theme.css @@ -183,7 +183,7 @@ body { display: block; position: relative; height: 1px; - width:100%; + width: 100%; background: #efefef; margin: 10px 0; } @@ -290,7 +290,7 @@ body { } .panel-item.panel-item-rgb { - background: #909090; + background: #009688; border-radius: 30px; color: #fff; margin: 10px 0; @@ -300,15 +300,12 @@ body { height: 50px; width: 100%; box-shadow: 0 1px 1.5px 0 rgba(0, 0, 0, .12), 0 1px 1px 0 rgba(0, 0, 0, .24); - transition: 0.5s; + transition: 1s; user-select: none; } .popover { - position: fixed; - z-index: 1000; width: 300px; - /*height: 200px;*/ box-shadow: 0px 5px 5px -3px rgba(0, 0, 0, 0.2), 0px 8px 10px 1px rgba(0, 0, 0, 0.14), 0px 3px 14px 2px rgba(0, 0, 0, 0.12); max-width: none; border-radius: 0; @@ -323,6 +320,35 @@ body { padding: 0; } +.rgb-widget-form { + padding: 10px; +} + +.sp-container { + display: block; + border-radius: 0; + background-color: transparent; + border: none; + padding: 0; +} + +.sp-picker-container { + width: 100%; + border: none; +} + +.sp-picker-container, .sp-palette-container { + float: none; + padding: 2px 0 0 0; + margin: 0; +} + +@media (min-width: 767px) { + .popover { + width: 500px; + } +} + /* Snackbar fixes */ #snackbar-container { position: fixed; @@ -442,7 +468,7 @@ body.login-body { color: #666; } -.material-table thead a:hover,.material-table thead a:active { +.material-table thead a:hover, .material-table thead a:active { color: #373737; text-decoration: none; } diff --git a/web/css/panel.css b/web/css/panel.css index b458711..84ba4a3 100644 --- a/web/css/panel.css +++ b/web/css/panel.css @@ -1,5 +1,3 @@ - - /* Content loader */ #loader { position: relative; diff --git a/web/css/theme.css b/web/css/theme.css index 1d3e23a..cb1b011 100644 --- a/web/css/theme.css +++ b/web/css/theme.css @@ -5966,28 +5966,6 @@ button.close { -webkit-box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.4); box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.4); } -.btn-default:after { - content: ""; - display: block; - position: absolute; - width: 100%; - height: 100%; - top: 0; - left: 0; - background-image: -webkit-radial-gradient(circle, #444444 10%, transparent 10.01%); - background-image: radial-gradient(circle, #444444 10%, transparent 10.01%); - background-repeat: no-repeat; - background-size: 1000% 1000%; - background-position: 50%; - opacity: 0; - pointer-events: none; - transition: background .5s, opacity 1s; -} -.btn-default:active:after { - background-size: 0% 0%; - opacity: .2; - transition: 0s; -} .btn-primary { position: relative; } @@ -6002,28 +5980,6 @@ button.close { -webkit-box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.4); box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.4); } -.btn-primary:after { - content: ""; - display: block; - position: absolute; - width: 100%; - height: 100%; - top: 0; - left: 0; - background-image: -webkit-radial-gradient(circle, #ffffff 10%, transparent 10.01%); - background-image: radial-gradient(circle, #ffffff 10%, transparent 10.01%); - background-repeat: no-repeat; - background-size: 1000% 1000%; - background-position: 50%; - opacity: 0; - pointer-events: none; - transition: background .5s, opacity 1s; -} -.btn-primary:active:after { - background-size: 0% 0%; - opacity: .2; - transition: 0s; -} .btn-success { position: relative; } @@ -6038,28 +5994,6 @@ button.close { -webkit-box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.4); box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.4); } -.btn-success:after { - content: ""; - display: block; - position: absolute; - width: 100%; - height: 100%; - top: 0; - left: 0; - background-image: -webkit-radial-gradient(circle, #ffffff 10%, transparent 10.01%); - background-image: radial-gradient(circle, #ffffff 10%, transparent 10.01%); - background-repeat: no-repeat; - background-size: 1000% 1000%; - background-position: 50%; - opacity: 0; - pointer-events: none; - transition: background .5s, opacity 1s; -} -.btn-success:active:after { - background-size: 0% 0%; - opacity: .2; - transition: 0s; -} .btn-info { position: relative; } @@ -6074,28 +6008,6 @@ button.close { -webkit-box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.4); box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.4); } -.btn-info:after { - content: ""; - display: block; - position: absolute; - width: 100%; - height: 100%; - top: 0; - left: 0; - background-image: -webkit-radial-gradient(circle, #ffffff 10%, transparent 10.01%); - background-image: radial-gradient(circle, #ffffff 10%, transparent 10.01%); - background-repeat: no-repeat; - background-size: 1000% 1000%; - background-position: 50%; - opacity: 0; - pointer-events: none; - transition: background .5s, opacity 1s; -} -.btn-info:active:after { - background-size: 0% 0%; - opacity: .2; - transition: 0s; -} .btn-warning { position: relative; } @@ -6110,28 +6022,6 @@ button.close { -webkit-box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.4); box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.4); } -.btn-warning:after { - content: ""; - display: block; - position: absolute; - width: 100%; - height: 100%; - top: 0; - left: 0; - background-image: -webkit-radial-gradient(circle, #ffffff 10%, transparent 10.01%); - background-image: radial-gradient(circle, #ffffff 10%, transparent 10.01%); - background-repeat: no-repeat; - background-size: 1000% 1000%; - background-position: 50%; - opacity: 0; - pointer-events: none; - transition: background .5s, opacity 1s; -} -.btn-warning:active:after { - background-size: 0% 0%; - opacity: .2; - transition: 0s; -} .btn-danger { position: relative; } @@ -6146,28 +6036,6 @@ button.close { -webkit-box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.4); box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.4); } -.btn-danger:after { - content: ""; - display: block; - position: absolute; - width: 100%; - height: 100%; - top: 0; - left: 0; - background-image: -webkit-radial-gradient(circle, #ffffff 10%, transparent 10.01%); - background-image: radial-gradient(circle, #ffffff 10%, transparent 10.01%); - background-repeat: no-repeat; - background-size: 1000% 1000%; - background-position: 50%; - opacity: 0; - pointer-events: none; - transition: background .5s, opacity 1s; -} -.btn-danger:active:after { - background-size: 0% 0%; - opacity: .2; - transition: 0s; -} .btn-link { position: relative; } diff --git a/web/js/panel.js b/web/js/panel.js index ee6f770..af5fa83 100644 --- a/web/js/panel.js +++ b/web/js/panel.js @@ -41,7 +41,15 @@ function onMessage(e) { switch (data.type) { case 'init': $.each(data.items, function (key, value) { - updateItemValue(value.id, value.type, value.value) + if (value.type == 30) { + updateRGB(value.id, value.value); + } else { + if (value.value != 'N/A') { + saveItemValue(id, value.value); + } + + updateItemValue(value.id, value.type, value.value); + } }); afterConnected(); @@ -68,13 +76,15 @@ function afterConnected() { }); } -function send(msg) { - if (typeof msg != "string") { - msg = JSON.stringify(msg); +function send(data) { + console.log(data); + + if (typeof data != "string") { + data = JSON.stringify(data); } if (WS && WS.readyState == 1) { - WS.send(msg); + WS.send(data); } } @@ -82,6 +92,20 @@ function updateValue(data) { updateItemValue(data.item_id, data.item_type, data.value); } +function updateRGB(itemId, data) { + itemValues[itemId] = data; + + if (data.mode == 'static' || data.mode == 'fade') { + $('.panel-item-rgb[data-item-id="' + itemId + '"]').attr('style', 'background: rgb(' + data.red + ',' + data.green + ',' + data.blue + ')'); + } + + $('#rgb-widget-wave-fade-time').val(data.fade_time); + + if (data.mode == 'fade' || data.mode == 'wave') { + $('#rgb-widget-wave-color-time').val(data.color_time); + } +} + function itemSwitchOn(itemId) { var $item = $('.panel-item-switch[data-item-id="' + itemId + '"]'); $item.removeClass('off'); @@ -96,12 +120,22 @@ function itemSetValue(itemId, value) { $('.panel-item-variable[data-item-id="' + itemId + '"] > .item-variable-value').html(value); } +function saveItemValue(itemId, value) { + itemValues[itemId] = value; +} + +function getSavedItemValue(itemId) { + return itemValues[itemId]; +} + function updateItemValue(id, type, value) { type = parseInt(type); switch (type) { case 10: // Switch - if (Boolean(value)) { + value = Boolean(value); + + if (value) { itemSwitchOn(id); } else { itemSwitchOff(id); @@ -118,189 +152,226 @@ function updateItemValue(id, type, value) { itemSetValue(id, value + '%'); break; case 25: // Variable boolean - value = Boolean(value) ? 'да' : 'нет'; + if (Boolean(value)) { + if (value != 'N/A') { + value = 'да'; + } + } else { + value = 'нет'; + } itemSetValue(id, value); break; case 26: // Variable boolean door if (value) { - value = 'открыто'; + if (value != 'N/A') { + value = 'открыто'; + } } else { value = 'закрыто'; } itemSetValue(id, value); - break; - case 30: // RGB - itemValues[id] = value; - // TODO - // if (typeof value === 'string') { - // $('.item-rgb[data-item-id="' + id + '"]') - // .find('.rgb-mode[data-mode="' + value + '"]') - // .addClass('active'); - // } else { - // var $colorPicker = $('#colorpicker-' + id); - // - // $colorPicker.spectrum('set', 'rgb(' + value[0] + ', ' + value[1] + ', ' + value[2] + ')'); - // - // $('.item-rgb .rgb-mode').removeClass('active'); - // } - break; } } $(document).ready(function () { - // Event listeners $('.panel-item-switch').click(function (e) { e.preventDefault(); - var item_id = $(this).data('item-id'); - var action = $(this).hasClass('off') ? 'turnON' : 'turnOFF'; + var $this = $(this); + + var item_id = $this.data('item-id'); send({ - "type": action, + "type": $this.hasClass('off') ? 'turnON' : 'turnOFF', "item_id": item_id }); - - return false; }); $('.panel-item-variable').tooltip(); - $('.panel-item-rgb').popover({ - html: true, - placement: 'bottom', - trigger: 'click', - content: function () { - var source = $("#rgb-item-widget-popover-content").html(); - var template = Handlebars.compile(source); + // RGB Widget + $('.panel-item-rgb') + .popover({ + html: true, + placement: 'bottom', + trigger: 'click', + container: 'body', + content: function () { + var source = $("#rgb-item-widget-popover-content").html(); + var template = Handlebars.compile(source); - return template({ - item_id: $(this).data('item-id') + return template({ + item_id: $(this).data('item-id') + }); + } + }) + // On popover init + .on('inserted.bs.popover', function () { + var item_id = $(this).data('item-id'); + + // Init colorpicker + var $colorPicker = $('body').find('.rgb-widget-colorpicker[data-item-id="' + item_id + '"]').spectrum({ + flat: true, + showInput: false, + showButtons: false, + preferredFormat: 'rgb' }); - } - }).on('inserted.bs.popover', function (e) { - var $colorPicker = $(this).parent().find('input').spectrum({ - flat: true, - showInput: true, - showButtons: false, - preferredFormat: 'rgb', - dragstop: function (color) { - console.log($(this)); - var item_id = $(this).data('item-id'); + + var savedItemValue = getSavedItemValue(item_id); + + // Set colorpicker value + if (savedItemValue != null) { + $colorPicker.spectrum('set', 'rgb(' + savedItemValue['red'] + ',' + savedItemValue['green'] + ',' + savedItemValue['blue'] + ')'); + } + + // Set mode and variables + if (savedItemValue.mode == 'static') { + $('.rgb-widget-mode-static').tab('show'); + } else if (savedItemValue.mode == 'wave') { + $('#rgb-widget-wave-color-time').val(savedItemValue.color_time); + $('#rgb-widget-fade-color-time').val(savedItemValue.color_time); + + $('.rgb-widget-mode-wave').tab('show'); + } else if (savedItemValue.mode == 'fade') { + $('#rgb-widget-wave-color-time').val(savedItemValue.color_time); + $('#rgb-widget-fade-color-time').val(savedItemValue.color_time); + + $('.rgb-widget-mode-fade').tab('show'); + } + + $('#rgb-widget-static-fade-time').val(savedItemValue.fade_time); + $('#rgb-widget-wave-fade-time').val(savedItemValue.fade_time); + $('#rgb-widget-fade-fade-time').val(savedItemValue.fade_time); + + // On color select + $colorPicker.on("dragstop.spectrum", function (e, color) { var red = Math.round(color._r); var green = Math.round(color._g); var blue = Math.round(color._b); - // - // var fade = ($('.fade-checkbox[data-item-id="' + item_id + '"]:checked').length > 0); - // - // send({ - // 'type': 'rgb', - // 'item_id': item_id, - // 'fade': fade, - // 'red': red, - // 'green': green, - // 'blue': blue - // }); - $('.panel-item-rgb[data-item-id="' + item_id + '"]').attr('style', 'background: rgb(' + red + ',' + green + ',' + blue + ')'); - } + + var $this = $(this); + var itemId = $this.data('item-id'); + + $('.panel-item-rgb[data-item-id="' + itemId + '"]') + .attr('style', 'background-color: rgb(' + red + ',' + green + ',' + blue + ')'); + + var modeId = $this.parents('.tab-pane').attr('id'); + + if (modeId == 'rgb-widget-static') { + send({ + "type": "rgb", + "item_id": item_id, + "fade_time": parseInt($('#rgb-widget-static-fade-time').val()), + "mode": "static", + "red": red, + "green": green, + "blue": blue + }); + } else if (modeId == 'rgb-widget-fade') { + send({ + "type": "rgb", + "item_id": item_id, + "fade_time": parseInt($('#rgb-widget-fade-fade-time').val()), + "color_time": parseInt($('#rgb-widget-fade-color-time').val()), + "mode": "fade", + "red": red, + "green": green, + "blue": blue + }); + } + }); + + $('.btn-save-times').click(function (e) { + e.preventDefault(); + + var mode = $(this).data('mode'); + + if (mode == 'wave') { + send({ + "type": "rgb", + "item_id": item_id, + "mode": "wave", + "fade_time": parseInt($('#rgb-widget-wave-fade-time').val()), + "color_time": parseInt($('#rgb-widget-wave-color-time').val()) + }); + } else if (mode == 'fade') { + var color = $('.rgb-widget-colorpicker-fade').spectrum('get'); + var red = Math.round(color._r); + var green = Math.round(color._g); + var blue = Math.round(color._b); + + if (savedItemValue != null) { + send({ + "type": "rgb", + "item_id": item_id, + "mode": "fade", + "fade_time": parseInt($('#rgb-widget-fade-fade-time').val()), + "color_time": parseInt($('#rgb-widget-fade-color-time').val()), + "red": red, + "green": green, + "blue": blue + }); + } else { + send({ + "type": "rgb", + "item_id": item_id, + "mode": "fade", + "fade_time": parseInt($('#rgb-widget-fade-fade-time').val()), + "color_time": parseInt($('#rgb-widget-fade-color-time').val()) + }); + } + } + }); + + $('.rgb-widget-popover-content[data-item-id="' + item_id + '"]').on('click', '.rgb-widget-mode', function (e) { + var $this = $(this); + + if ($this.attr('aria-expanded') == 'true') { + return; + } + + if ($this.hasClass('rgb-widget-mode-static')) { + var color = $('.rgb-widget-colorpicker-static').spectrum('get'); + var red = Math.round(color._r); + var green = Math.round(color._g); + var blue = Math.round(color._b); + + send({ + "type": "rgb", + "item_id": item_id, + "fade_time": parseInt($('#rgb-widget-static-fade-time').val()), + "mode": "static", + "red": red, + "green": green, + "blue": blue + }); + } else if ($this.hasClass('rgb-widget-mode-wave')) { + send({ + "type": "rgb", + "item_id": item_id, + "mode": "wave", + "fade_time": parseInt($('#rgb-widget-wave-fade-time').val()), + "color_time": parseInt($('#rgb-widget-wave-color-time').val()) + }); + } else if ($this.hasClass('rgb-widget-mode-fade')) { + var color = $('.rgb-widget-colorpicker-fade').spectrum('get'); + var red = Math.round(color._r); + var green = Math.round(color._g); + var blue = Math.round(color._b); + + send({ + "type": "rgb", + "item_id": item_id, + "mode": "fade", + "fade_time": parseInt($('#rgb-widget-fade-fade-time').val()), + "color_time": parseInt($('#rgb-widget-fade-color-time').val()) + }); + } + }); }); - - var item_id = $colorPicker.data('item-id'); - - if (Boolean(itemValues[item_id]) != false) { - $colorPicker.spectrum('set', itemValues[item_id]); - } - - $colorPicker.on("dragstop.spectrum", function (e, color) { - var red = Math.round(color._r); - var green = Math.round(color._g); - var blue = Math.round(color._b); - - $('.panel-item-rgb[data-item-id="' + $(this).data('item-id') + '"]').attr('style', 'background-color: rgb(' + red + ',' + green + ',' + blue + ')') - }); - }); - - // TODO: - // $('.rgb-colorpicker').spectrum({ - // showInput: true, - // showButtons: false, - // preferredFormat: 'rgb', - // change: function (color) { - // var item_id = $(this).data('item-id'); - // var red = Math.round(color._r); - // var green = Math.round(color._g); - // var blue = Math.round(color._b); - // - // var fade = ($('.fade-checkbox[data-item-id="' + item_id + '"]:checked').length > 0); - // - // send({ - // 'type': 'rgb', - // 'item_id': item_id, - // 'fade': fade, - // 'red': red, - // 'green': green, - // 'blue': blue - // }); - // } - // }); - - // $('.fade-checkbox').each(function () { - // var localStorageValue = window.localStorage.getItem('fade-checkbox-' + $(this).data('item-id')); - // - // console.log(localStorageValue); - // - // this.checked = localStorageValue != null && localStorageValue != 'false'; - // }); - - // initWebSocket(function () { - // $('input[type="checkbox"].item-switch-checkbox').click(function (e) { - // e.preventDefault(); - // - // var item_id = $(this).data('item-id'); - // var action = $(this).prop('checked') ? 'turnON' : 'turnOFF'; - // - // send({ - // "type": action, - // "item_id": item_id - // }); - // }); - - // Delegate click on block to checkbox - // $('.item-switch .info-box').click(function (e) { - // e.preventDefault(); - // - // if ($(e.target).is('.item-switch-checkbox')) { - // return false; - // } - // - // $(this).find('.item-switch-checkbox').click(); - // }); - - // $('.rgb-mode').click(function (e) { - // e.preventDefault(); - // - // var mode = $(this).data('mode'); - // var start = true; - // var item_id = $(this).parents('.item-rgb').data('item-id'); - // - // if ($(this).hasClass('active')) { - // start = false - // } - // - // send({ - // "type": "rgbMode", - // "item_id": item_id, - // "mode": mode, - // "start": start - // }); - // }); - - // $('.fade-checkbox').change(function (e) { - // window.localStorage.setItem('fade-checkbox-' + $(this).data('item-id'), this.checked); - // }); - // }); });