开发一个项目微信小程序享寄存,软硬件结合,软硬件通信以前没有做过,网上的资料也很少,踩了不少的坑,特此记录一下。首先硬件和服务器建立一个socket长链接,前端微信小程序给服务器,发出命令给服务器,开锁,服务器如何通知客户端呢?
二、解决方案在硬件客户端和服务器建立链接时,同时开启一个内部端口,进行监听
三、代码实现start.php代码
onMessage = function($connection, $buffer)
{
// $data数组格式,里面有uid,表示向那个uid的页面推送数据
$data = json_decode($buffer, true);
$uid = $data['uid'];
$openArr = config('lock.open');
$index = $data['index'];
// 通过workerman,向uid的页面推送数据
$ret = $this->sendMessageByUid($uid, self::hexToString($openArr[$index]));
// 返回推送结果
$connection->send($ret ? 'ok' : 'fail');
};
// ## 执行监听 ##
$inner_text_worker->listen();
}
public function onMessage($connection, $data)
{
$receiveData = explode(',',$data);
//判断是否是心跳包
if(!empty($receiveData) && $receiveData[0] == 'NBES') {
$send = explode('=',$receiveData[1]);
if(isset($connection->id) && !array_key_exists($connection->id,self::$worker->uidConnections)) {
self::$worker->uidConnections[$connection->id] = $connection;
}
//对应起来数据库里面的柜子
$chest = Chest::getChestByGsm($send[1]);
if($chest->server_id != $connection->id) {
Chest::update(array('server_id'=>$connection->id,'simstatus'=>config('sim.status_normal')),array('bdz'=>$send[1]));
}
$connection->send($send[1]);
}else {
if(!empty($data)) {
$backSuccess = config('lock.backSuccess');
$backError = config('lock.backError');
$receive = self::stringToHexArray($data);
$boxOpenStatus = config('box.open');
$boxTrouble = config('box.trouble');
$closeSuccess = config('lock.closeSuccess');
$closeError = config('lock.closeError');
if($receive[0] == '0x8a') {
//读锁返回状态
$this->openReturnStatus($receive,$backError,$backSuccess,$boxOpenStatus,$boxTrouble,$connection);
}else if($receive[0] == '0x82'){
//关锁状态反馈
$this->closeReturnStatus($receive,$closeSuccess,$closeError,$boxTrouble,$boxOpenStatus,$connection);
}
}
}
}
public function onConnect($connection)
{
echo 'connect ok -'.$connection->id;
}
public function onClose($connection)
{
if(isset($connection->uid))
{
// 连接断开时删除映射
unset(self::$worker->uidConnections[$connection->uid]);
}
}
public function sendMessageByUid($uid, $message)
{
if(isset(self::$worker->uidConnections[$uid]))
{
$connection = self::$worker->uidConnections[$uid];
$connection->send($message);
return true;
}
return false;
}
public function onError($connection, $code, $msg)
{
echo "error $code $msgn";
}
public static function stringToHexArray($string)
{
$arr1 = str_split($string, 1);
foreach($arr1 as $akey=>$aval){
$arr1[$akey]="0x".bin2hex($aval);
}
return($arr1);
}
public static function hexToString($hex)
{
$myStr="";
for($i=0;isset($hex[$i]);$i++)
{
$myStr.= chr($hex[$i]);
}
return($myStr);
}
public function closeReturnStatus($receive,$closeSuccess,$closeError,$boxTrouble,$boxOpenStatus,$connection) {
if(in_array($receive,$closeSuccess)) {
$keys = array_keys($closeSuccess,$receive);
$key = $keys[0]+1;
$open = $boxOpenStatus['status_normal'];
$chest = Chest::get(array('server_id'=>$connection->id));
if(!empty($chest)) {
Box::update(array('open'=>$open),array('xsxh'=>$key,'cid'=>$chest->id));
}
}elseif (in_array($receive,$closeError)) {
$keys = array_keys($closeError,$receive);
$key = $keys[0]+1;
$status = $boxTrouble['status_padding'];
$chest = Chest::get(array('server_id'=>$connection->id));
if(!empty($chest)) {
Box::update(array('status'=>$status),array('xsxh'=>$key,'cid'=>$chest->id));
}
}
}
private function openReturnStatus($receive,$backError,$backSuccess,$boxOpenStatus,$boxTrouble,$connection) {
//开门返回状态
$open = 1;
$trouble = 0;
$key = 1;
if(in_array($receive,$backSuccess)) {
$keys = array_keys($backSuccess,$receive);
$key = $keys[0]+1;
$open = $boxOpenStatus['status_padding'];
$trouble = $boxTrouble['status_normal'];
}else if(in_array($receive,$backError)) {
$keys = array_keys($backError,$receive);
$key = $keys[0]+1;
$open = $boxOpenStatus['status_normal'];
$trouble = $boxTrouble['status_delete'];
}
$chest = Chest::get(array('server_id'=>$connection->id));
if(!empty($chest)) {
Box::update(array('open'=>$open,'status'=>$trouble),array('xsxh'=>$key,'cid'=>$chest->id));
}
}
}
Socket代码,发送指令到内部端口
public static function openLock($id,$index) {
// 建立socket连接到内部推送端口
$client = stream_socket_client('tcp://127.0.0.1:5678', $errno, $errmsg, 1);
// 推送的数据,包含uid字段,表示是给这个uid推送
$data = array('uid' => $id, 'index' => $index);
// 发送数据,注意5678端口是Text协议的端口,Text协议需要在数据末尾加上换行符
fwrite($client, json_encode($data) . "n");
// 读取推送结果
return fread($client, 8192);
}
四、流程总结
首先硬件客户端和服务器建立一个socket链接,建立时开启一个内部端口进行监听,软件客户端(微信小程序或者app)发送http请求给服务器,服务器接受到请求,通过socket发送数据到内部端口,内部端口接受到数据发送指令给硬件客户端。



