大家好,我是物联好朋友小搜。
今天,我们结合前面的文章内容,进行一个简单的物联应用。
在物联网中最简单直接的应用就远程开关电灯,今天小搜将为大家一一讲述。
本文用到的技术和工具都相对简单,在阅读本文时,建议没有关注小搜往期文章的朋友回头去看看,有前面的一些知识有所了解。
回顾完全文后,正式进入主题。
一、设计一个简单实用的架构
从上图可以看出,云端需要建立三个服务,分别是:tcp服务、mqtt服务、websocket服务。
线下需要准备串口服务器(tcp转485)、485硬件(继电器)。
控制端则可以是浏览或者App,当然小程序也可以,只要支持websocket的客户端都行。
二、服务器搭建
我们将用上一期学到的swoole建立websocket服务器应用到这里,做到真正的学以致用。然后在这个基础上,再建立一个tcp服务器。
代码相当简单,暂不考虑安全性,稳定性等方面(这些需要大家自己深入,小搜只能把朋友们带进门)。
下面是详细代码:
tcpserver.php
<?php use TrytoMqtt\Client; require_once __DIR__ . '/vendor/autoload.php'; $device_maps = []; //创建Server对象,监听 localhost :39001端口 $serv = new Swoole\ server ("localhost", 39001); $options = [ 'clean_session' => false, 'client_id' => 'demo-tcpserver-123456', 'username' => '', 'password' => '', ]; $mqtt = new Client('localhost', 1883, $options); $serv->on('WorkerStart', function ($serv, $worker_id) use ($mqtt) { echo "tcp worker start\r\n"; $mqtt->onConnect = function ($mqtt) { $mqtt->subscribe('/websocket485'); }; $mqtt->onMessage = function ($topic, $content) use ($serv) { global $device_maps; var_dump($device_maps); echo date('Y-m-d H:i:s') . "Mqtt Receive=================================\r\n"; var_dump($topic, $content); $ json = json_decode($content, true); var_dump($json); if (isset($device_maps[$json['device']])) { var_dump($json[' msg ']); $data = json_decode($json['msg'], true); echo "send instruction \n"; $serv->send($device_maps[$json['device']]['fd'], hex2bin(str_replace(' ', '', $data['instruction']))); } }; $mqtt->onError = function ($ exception ) use ($mqtt) { echo "error\n"; }; $mqtt->on close = function () { echo "close\n"; }; $mqtt->connect(); }); //监听连接进入事件 $serv->on('Connect', function ($serv, $fd) { echo "Client: Connect.\n"; }); //监听数据接收事件 $serv->on('Receive', function ($serv, $fd, $from_id, $msg) use ($mqtt) { global $device_maps; var_dump($device_maps); echo date('Y-m-d H:i:s') . "=================================\r\n"; $json = json_decode($msg, true); var_dump($json); //todo已经注册的TCP串口服务器,不能再注册 if (is_array($json) && isset($json['reg'])) { if (!isset($device_maps[$json['reg']])) { $device_maps[$json['reg']] = ['device' => $json['reg'], 'fd' => $fd]; echo "device register done"; } else { echo "device has been registered"; } } else { if (!is_array($json)) { foreach ($device_maps as $map) { if ($map['fd'] == $fd) { var_dump($map); $msg = json_encode(['device' => $map['device'], 'msg' => bin2hex($msg)]); break ; } } } } $mqtt->publish('/tcp485', $msg); }); //监听连接关闭事件 $serv->on('Close', function ($serv, $fd) { echo "Client: Close.\n"; global $device_maps; foreach ($device_maps as $key => $map) { if ($map['fd'] == $fd) { unset($device_maps[$key]); echo "remove " . $key; break; } } }); //启动服务器 $serv->start();
websocket.php
<?php use TrytoMqtt\Client; require_once __DIR__ . '/vendor/autoload.php'; $socket_maps = []; $server = new swoole_websocket_server("localhost", 39002); $options = [ 'clean_session' => false, 'client_id' => 'demo-websocket-123456', 'username' => '', 'password' => '', ]; $mqtt = new Client('localhost', 1883, $options); $server->on('WorkerStart', function ($serv, $worker_id) use ($mqtt) { echo "websocket worker start\r\n"; $mqtt->onConnect = function ($mqtt) { $mqtt->subscribe('/tcp485'); }; $mqtt->onMessage = function ($topic, $content) use ($serv) { global $socket_maps; var_dump($socket_maps); echo "Mqtt=================================" . date('Y-m-d H:i:s') . "\r\n"; var_dump($topic, $content); $json = json_decode($content, true); var_dump($json); if (isset($socket_maps[$json['device']])) { var_dump($json['msg']); echo "response \n"; $serv->push($socket_maps[$json['device']]['fd'], $json['msg']); } }; $mqtt->onError = function ($exception) use ($mqtt) { echo "error\n"; }; $mqtt->onClose = function () { echo "close\n"; }; $mqtt->connect(); }); $server->on('open', function ($server, $req) { echo "connection open: {$req->fd}\n"; }); $server->on('message', function ($server, $frame) use ($mqtt) { global $socket_maps; echo "received tcp message: {$frame->data}" . date('Y-m-d H:i:s') . "\n"; $server->push($frame->fd, $frame->data); var_dump($socket_maps); $json = json_decode($frame->data, true); var_dump($json); //已经注册的客户端不能再注册 if (isset($json['reg'])) { if (!isset($socket_maps[$json['reg']])) { $socket_maps[$json['reg']] = ['device' => $json['reg'], 'fd' => $frame->fd]; echo "websocket client register done"; } else { echo "websocket client has been registered"; } $msg = $frame->data; } else { foreach ($socket_maps as $map) { if ($map['fd'] == $frame->fd) { var_dump($map); $msg = json_encode(['device' => $map['device'], 'msg' => $frame->data]); break; } } } $mqtt->publish('/websocket485', $msg); }); $server->on('close', function ($server, $fd) { global $socket_maps; echo "connection close: {$fd}\n"; foreach ($socket_maps as $key => $map) { if ($map['fd'] == $fd) { unset($socket_maps[$key]); echo "remove " . $key; break; } } }); $server->start();
三、调试
服务器搭建好后,接着是调试。调试只需要在服运器运行上述两个文件,具体操作请回看往期的文章,小搜这里上一张动图,朋友们看看最终效果。
从上图可以看出,Websocket客户端与TCP客户端已经能够正常通讯。
想 获取源码 的朋友们可以私信小搜:先 关注 ,然后 私信 小搜,小搜收到后会尽快回复。
下一期我们结合这两个做好了的服务器实现web浏览器控制实际硬件的示例,持续关注小搜将会为大家带来更多实用文章,我们下期再见。