diff --git a/models/Board.php b/models/Board.php index dbfd187..53c0156 100644 --- a/models/Board.php +++ b/models/Board.php @@ -2,6 +2,7 @@ namespace app\models; +use app\models\query\BoardQuery; use Yii; use yii\db\ActiveRecord; use yii\helpers\ArrayHelper; diff --git a/models/Item.php b/models/Item.php index cb88de8..c85fe8b 100644 --- a/models/Item.php +++ b/models/Item.php @@ -36,6 +36,7 @@ class Item extends ActiveRecord const TYPE_VARIABLE_HUMIDITY = 22; const TYPE_VARIABLE_LIGHT = 23; const TYPE_RGB = 30; + const TYPE_PLANT = 40; const VALUE_ON = 1; const VALUE_OFF = 0; @@ -148,6 +149,7 @@ class Item extends ActiveRecord self::TYPE_VARIABLE_HUMIDITY => 'Переменная влажность', self::TYPE_VARIABLE_LIGHT => 'Переменная освещенность', self::TYPE_RGB => 'RGB', + self::TYPE_PLANT => 'Растение', ]; } diff --git a/models/ItemWidget.php b/models/ItemWidget.php index 9b495ee..adc0498 100644 --- a/models/ItemWidget.php +++ b/models/ItemWidget.php @@ -27,6 +27,7 @@ class ItemWidget extends ActiveRecord const TYPE_SWITCH = 10; const TYPE_VARIABLE = 20; const TYPE_RGB = 30; + const TYPE_PLANT = 40; const VALUE_TYPE_BOOLEAN = 10; const VALUE_TYPE_DOOR = 20; @@ -125,6 +126,7 @@ class ItemWidget extends ActiveRecord self::TYPE_SWITCH => 'Переключатель', self::TYPE_VARIABLE => 'Переменная', self::TYPE_RGB => 'RGB', + self::TYPE_PLANT => 'Растение', ]; } diff --git a/models/ItemWidgetQuery.php b/models/ItemWidgetQuery.php index d9a33d0..f29079f 100644 --- a/models/ItemWidgetQuery.php +++ b/models/ItemWidgetQuery.php @@ -43,6 +43,14 @@ class ItemWidgetQuery extends ActiveQuery return $this->andWhere(['type' => ItemWidget::TYPE_RGB]); } + /** + * @return $this + */ + public function plant() + { + return $this->andWhere(['type' => ItemWidget::TYPE_PLANT]); + } + /** * @inheritdoc * @return ItemWidget[]|array diff --git a/models/BoardQuery.php b/models/query/BoardQuery.php similarity index 80% rename from models/BoardQuery.php rename to models/query/BoardQuery.php index d0c164f..560059e 100644 --- a/models/BoardQuery.php +++ b/models/query/BoardQuery.php @@ -1,13 +1,16 @@ handleTrig($from, $user, $data); case 'debug_send_to_board': return $this->handleDebugSendToBoard($from, $user, $data); + case 'do_watering': + return $this->handleDoWatering($from, $user, $data); } return $this->log("Unknown command from user: $msg"); @@ -370,6 +372,9 @@ class CoreServer implements MessageComponentInterface case 'ping': $this->handleBoardPingMessage($from, $board); break; + case 'watered': + $this->handleBoardWateredMessage($data, $from, $board); + break; default: $this->log("Unknown command: \"{$data['type']}\""); break; @@ -609,6 +614,68 @@ class CoreServer implements MessageComponentInterface return true; } + /** + * @param ConnectionInterface $from + * @param User $user + * @param array $data + * @throws NotSupportedException + */ + protected function handleDoWatering($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_PLANT) { + return $from->send(Json::encode([ + 'type' => 'error', + 'message' => 'Данный тип устройства не является Plant', + ])); + } + + $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' => 'Устройство не подключено', + ])); + } + + $this->sendToBoard($board->id, [ + 'type' => 'do_watering', + 'item_id' => $item->id, + ]); + + break; + } + + $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 = 'do_watering'; + + if (!$history->save(false)) { + $this->log("Cannot log:"); + var_dump($history->errors); + } + + return true; + } + /** * @param ConnectionInterface $from * @param User $user @@ -1170,6 +1237,35 @@ class CoreServer implements MessageComponentInterface ])); } + /** + * @param $data + * @param ConnectionInterface $from + * @param Board $board + * @throws NotFoundHttpException + */ + public function handleBoardWateredMessage($data, $from, $board) + { + $itemId = (integer)$data['item_id']; + + $item = Item::findOne([ + 'id' => $itemId, + 'board_id' => $board->id, + ]); + + if (!$item) { + $this->log("Board [{$board->id}] tried to use unknown item"); + throw new NotFoundHttpException('Item does not exist'); + } + + $this->sendUsers([ + 'type' => 'watered', + 'item_id' => $item->id, + ]); + + $this->logItemValue($item, 'watered'); + $this->saveItemValue($item->id, 'watered', $item->type); + } + /** * @param string $value * @return array diff --git a/views/panel/_plant.php b/views/panel/_plant.php new file mode 100644 index 0000000..55a3d18 --- /dev/null +++ b/views/panel/_plant.php @@ -0,0 +1,25 @@ + + +
+
+
+ getName() ?> +
+
+
+ +
+
0 %
+
+ +
+
diff --git a/views/panel/index.php b/views/panel/index.php index 3303d1d..caf9595 100644 --- a/views/panel/index.php +++ b/views/panel/index.php @@ -66,6 +66,13 @@ $this->title = 'Панель Управления'; ]) ?> +
+ getItemWidgets()->plant()->active()->all() as $widget): ?> + render('_plant', [ + 'widget' => $widget, + ]) ?> + +
diff --git a/web/css/panel.css b/web/css/panel.css index 9d7cb51..10c82c2 100644 --- a/web/css/panel.css +++ b/web/css/panel.css @@ -83,3 +83,47 @@ /* 5 columns for larger screens */ .col-md-6.masonry-item { width: 100%; } } + +.panel-item-plant { + width: 100%; + background: #009688; + border-radius: 2px; + box-shadow: 0 1px 1.5px 0 rgba(0, 0, 0, .12), 0 1px 1px 0 rgba(0, 0, 0, .24); + color: #fff; + margin: 10px 0; + user-select: none; +} + +.panel-item-plant-name { + background: rgba(0, 0, 0, 0.3); + text-align: center; + font-size: 15px; + padding: 5px 0; + font-weight: bold; +} + +.panel-item-plant-actions { + padding: 10px; +} + +.panel-item-plant-row { + display: flex; + position: relative; + width: 100%; + padding-top: 15px; +} + +.panel-item-plant-soil-moisture { + font-size: 30px; + line-height: 45px; + text-align: center; + width: 50%; +} + +.panel-item-plant-icon { + font-size: 45px; + text-align: center; + line-height: 1; + width: 50%; + border-right: 1px solid rgba(255,255,255,0.3); +} diff --git a/web/js/panel.js b/web/js/panel.js index b6615f6..1aa4798 100644 --- a/web/js/panel.js +++ b/web/js/panel.js @@ -68,6 +68,15 @@ function onMessage(e) { case 'rgb': updateRGB(data.item_id, data); break; + case 'soil_moisture': + itemValues[data.item_id] = data.value; + + $('.panel-item-plant[data-item-id="' + data.item_id + '"]').find('.panel-item-plant-soil-moisture').html(data.value + ' %'); + + break; + case 'watered': + showSuccessMessage('Растение полито'); + break; case 'error': showErrorMessage(data.message); break; @@ -303,10 +312,17 @@ $(document).ready(function () { send({ type: 'debug_send_to_board', board_id: parseInt($('#send-board-board_id').val()), - message: $('#send-board-message').val(), + message: $('#send-board-message').val() }); + }).on('click', '.btn-plant-do-watering', function (e) { + e.preventDefault(); - return false; + var item_id = $(this).parents('.panel-item-plant').data('item-id'); + + send({ + type: 'do_watering', + item_id: item_id + }); }); // RGB Widget