硬件也没那么难
本质都是联网,然后发送指令。
提供接口地址和路径,机器定时调用。
然后发送反馈信息。
机器识别后,进行操作。
比如停车设备。
需要在设备中配置一下接口地址(ip+端口)。
<?php
/**
* 停车进出
*/
namespace Car\Action;
use Common\Util\RS485Util;
class IndexAction extends CommonAction
{
/**
* 获取企业列表
*
* @return void
*/
public function receive(){
$start_time = microtime(true);
// 获取数据,进行解析
$in_data = $GLOBALS["HTTP_RAW_POST_DATA"];
$in_data = json_decode($in_data,true);
// 处理回执
if (array_key_exists('CommondRespond',$in_data)) {
setlog($in_data,'回执');
return null;
}
// 处理心跳
if (array_key_exists('KeepAlive',$in_data)) {
setlog($in_data,'心跳');
/**
"KeepAlive": {
"ROMID": "ffff2941001b763e",
"SN": "5200500082",
"ipaddr": "192.168.0.98"
}
*/
// 查询到设备后,将其设置为在线,并更新时间
$sn = $in_data['KeepAlive']['SN'];
$device = M('device');
$save_data = [];
$save_data['online'] = 1;
$save_data['update_time'] = date('Y-m-d H:i:s');
$device->where(['device_type'=>2,'mac_address'=>$sn])->save($save_data);
return null;
}
// 车辆进出主要逻辑
if (array_key_exists('AlarmInfoPlate',$in_data)) {
/**
"AlarmInfoPlate": {
"resultType": 0, // 识别结果类型
"result": {
"PlateResult": {
"license": "京AV6L36", // 车牌
"platecolor": "蓝", // 蓝
"recotime": "2021-02-02 13:41:10",
"imageFile": "",
"imageFileLen": 0,
"imageFragmentFile": "",
"imageFragmentFileLen": 0
}
},
"seriaIno": "ffff2941001b763e",
"romid": "ffff2941001b763e",
"sn": "5200500082"
}
*/
// 默认不开门
$action = "close";
// 第一行信息
$messageOne = "";
// 第二行信息
$messageTwo = "";
// 获取基本数据
$resultType = $in_data['AlarmInfoPlate']['resultType'];
$sn = $in_data['AlarmInfoPlate']['sn'];
$carNumber = $in_data['AlarmInfoPlate']['result']['PlateResult']['license'];
$recordTime = $in_data['AlarmInfoPlate']['result']['PlateResult']['recotime'];
// car_info,customer_visitor,car_record,user_customer_village,device
// 判断车牌是否为空
// 地上车,不可进入地下 "你的车辆是地上车辆,暂不可进入地下车库"
// 到期不可以,不可进入 "您的车辆停放时间已到期"
// 快到期,可以进,提示快到期 "车辆停放时间快到期,请尽快缴费"
// 处理好访客和业主信息
// 添加好进出记录
// 访客进,“欢迎光临!”,访客出,“欢迎下次光临!”
// 业主进,“欢迎回家!”,业主出,“一路顺风!”
// 陌生车辆 "陌生车辆,请联系管理员!"
$car_info = M('car_info');
$customer_visitor = M('customer_visitor');
$car_record = M('car_record');
$user_customer_village = M('user_customer_village');
$device = M('device');
$messageOne = $carNumber;
if ($carNumber && $sn) {
$device_info = $device->where(['mac_address'=>$sn,'device_type'=>2])->find();
if (!$device_info) {
setlog($in_data,'设备不存在');
return null;
}
// 确定小区id
$village_id = $device_info['village_id'];
// 判断车辆是否属于该小区
$car_info_info = $car_info->where(['number'=>$carNumber,'village_id'=>$village_id])->find();
$customer_visitor_info = $customer_visitor->where(['car_number'=>$carNumber,'village_id'=>$village_id])->find();
if ($device_info['device_area'] == 1) { // 入口
if ($car_info_info) { // 车辆信息存在
// 判断是否到期
if (strtotime($car_info_info['valid_date']) < strtotime(date('Y-m-d')) ){
$messageTwo = "您的车辆停放时间已到期";
$this->Response($messageOne,$messageTwo,$action);
}
if ($device_info['type'] == 1 && $car_info_info['parking_type'] == 0) { // 地下
$messageTwo = "你的车辆是地上车辆,暂不可进入地下车库";
$this->Response($messageOne,$messageTwo,$action);
}
// 增加业主进入记录
$user_customer_village_info = $user_customer_village->where(['house_id'=>$car_info_info['house_id'],'role'=>0])->find();
$record_add_data = [
'user_id' => $user_customer_village_info['customer_id'],
'device_id' => $device_info['id'],
'village_id' => $device_info['village_id'],
'create_time' => $recordTime,
'device_sn' => $sn,
'car_id' => $car_info_info['id'],
'type' => 2,
'user_type' => 0 // 0 用户 1 访客
];
$car_record->add($record_add_data);
$action = 'open';
$messageTwo = "欢迎回家!";
$this->Response($messageOne,$messageTwo,$action);
} else {
// 看看是否是访客
if ($customer_visitor_info) {
$action = 'open';
$messageTwo = "欢迎光临!";
$this->Response($messageOne,$messageTwo,$action);
} else {
$messageTwo = "陌生车辆,请联系管理员!";
$this->Response($messageOne,$messageTwo,$action);
}
}
} else { // 出口
if ($car_info_info) {
// 增加业主进入记录
$user_customer_village_info = $user_customer_village->where(['house_id'=>$car_info_info['house_id'],'role'=>0])->find();
$record_add_data = [
'user_id' => $user_customer_village_info['customer_id'],
'device_id' => $device_info['id'],
'village_id' => $device_info['village_id'],
'create_time' => $recordTime,
'device_sn' => $sn,
'car_id' => $car_info_info['id'],
'type' => 2,
'user_type' => 0 // 0 用户 1 访客
];
$car_record->add($record_add_data);
$action = 'open';
$messageTwo = "一路顺风!";
$this->Response($messageOne,$messageTwo,$action);
} else {
// 看看是否是访客
if ($customer_visitor_info) {
$action = 'open';
$messageTwo = "欢迎下次光临!";
$this->Response($messageOne,$messageTwo,$action);
} else {
$action = 'open';
$messageTwo = "陌生人,一路顺风!";
$this->Response($messageOne,$messageTwo,$action);
}
}
}
} else {
setlog($in_data,'信息识别有误');
return null;
}
}
/**
{
"Response": {
"barrier_control": { // 抬杆
"action": "open"
},
"trigger_data": { // 抓拍
"action": ""
},
"rs485_data": [{ // 透明传输,485语音指令,语音、显示、抬杆
"delay_time": 100,
"data": "/gAAF5lz/QAPAQBbbjJdufNKUjg0RzExTQ=="
},
{
"delay_time": 400,
"data": "/pgAbJdUAAAAAAAAAAAAAQEB/lxLiVkAAAAxAABsuUYAAAAwMDAwMDAwMDIsCQQAMDEwMTAxOTkxMj
MxEwAAAFWqAAA3MjIxMTEAAAgAEAABEQASAAAA0rvN + 87e vMr / AAEAAQABAGd8 ///Wi88="}
],
"whitelist_data": [{ // 白名单
"action": "add",
"plate_number": "粤B12345F",
"create_time": "2019-01-01 12:12:21",
"start_time": "2019-01-01 12:12:21",
"end_time": "2023-01-01 12:12:21",
"is_black_list": "no",
"time_match": "enable"
},
{
"action": "delete",
"plate_number": "京A12345"
}
]
}
}
*/
$end_time = microtime(true);
setlog("+++++++++++++++++车辆通行接口运行时间:".($end_time - $start_time)."ms");
}
public function Response($messageOne,$messageTwo,$action) {
$rs485Util = new RS485Util();
$voiceMsg = $rs485Util->changeCarStr($messageOne).$messageTwo;
$messageOne = $rs485Util->show($messageOne,31,'31','FF');
$messageTwo = $rs485Util->show($messageTwo,32,'31','00');
$voiceMsg = $rs485Util->Voice($voiceMsg);
$return_arr = [];
$return_arr['Response'] = [
'barrier_control' => [
'action' => $action
],
'rs485_data' => [
[
'delay_time'=>100,
'data'=>$messageOne
],
[
'delay_time'=>400,
'data'=>$messageTwo
],
[
'delay_time'=>400,
'data'=>$voiceMsg
],
]
];
setlog($return_arr);
$return_json = json_encode($return_arr);
$return_json = stripslashes($return_json);
$return_json = mb_convert_encoding($return_json, 'GBK', 'UTF-8');
echo $return_json;
return null;
}
}
这里比较难的就是处理语音和显示指令,用到了rs485协议。
<?php
namespace Common\Util;
class RS485Util
{
//拼接显示485数据 参数 $ln//行数 32 33 34 分别为二三四行(显示屏幕第几行文字)
// $sc//两行屏 32四行屏
// $mo//显示的数据是否滚动 00滚动 FF不滚动
public function show($str, $ln = '31', $sc = '31', $mo = '00')
{
$str = mb_convert_encoding($str, 'GBK', 'UTF-8');
$display = bin2hex($str); //字符串转换16进制
$a = strlen($str); //显示字符长度
$a1 = str_pad(dechex($a + 100), 4, "0", 0); //取4个字节
$strLength = dechex($a); //把十进制转换为十六进制。
$totalLength = str_pad(dechex($a + 100), 4, "0", 0); //数据总长
$packLength = str_pad(dechex($a + 81), 2, "0", 0); //本数据长度
$dataLength = str_pad(dechex($a + 62), 2, "0", 0); //数据长度
$line = $ln; //行数 32 33 34 分别为二三四行(显示屏幕第几行文字)
$screen = $sc; // 31两行屏 32四行屏
$motion = $mo; //显示的数据是否滚动 00滚动 FF不滚动
$contentLength = str_pad(dechex($a + 10), 2, "0", 0); //显示内容长度
$byteArray = "$display"; //显示内容
$strFormat = "FE98" . $totalLength . "9754000000000000000000010101FE5C4B89" . $packLength . "0000003100006CB9" . $dataLength . "0000003030303030303030" . $line . "2C0104" . $motion . "3031303130313939313233311300000055AA000037323231" . $screen . "31000008001000011100" . $contentLength . "000000" . $byteArray . "FF00010001000100677CFFFF";
$s = str_split($strFormat, 2); //字符转数组
$s1 = substr($strFormat, 2); //截取
//crc校验
$s2 = pack('H*', $s1); //吧数据存放到16进制字符串中
$crc485 = bin2hex($this->crc16($s2));
$ss1 = $s1 . $crc485;
//异或和校验
$o = $this->setSecretKey1($ss1);
$complete = strtoupper($strFormat . $crc485 . $o); //拼接完整的485数据
return base64_encode(hex2bin($complete));
}
/**
* 修改数字,防止读成一体
* @param $str
* @return string|string[]
*/
public function changeCarStr($str) {
// 替换数字
$str = str_replace("0","零",$str);
$str = str_replace("1","一",$str);
$str = str_replace("2","二",$str);
$str = str_replace("3","三",$str);
$str = str_replace("4","四",$str);
$str = str_replace("5","五",$str);
$str = str_replace("6","六",$str);
$str = str_replace("7","七",$str);
$str = str_replace("8","八",$str);
$str = str_replace("9","九",$str);
return $str;
}
public function Voice($str)
{
$str = mb_convert_encoding($str, 'GBK', 'UTF-8');
$display = bin2hex($str); //字符串转换16进制
$a = strlen($str); //显示字符长度
$strLength = dechex($a); //把十进制转换为十六进制。
$totalLength = str_pad(dechex($a + 10), 4, "0", 0); //数据总长
$packLength = str_pad(dechex($a + 2), 4, "0", 0); //数据长度
$byteArray = "$display"; //显示内容
$speech = "FE00" . $totalLength . "9973FD" . $packLength . "0100" . $byteArray . "";
$s = str_split($speech, 2); //字符转数组
$s1 = substr($speech, 2); //截取
//异或和校验
$o = str_pad($this->setSecretKey1($s1), 2, "0", 0);
$complete = $speech . $o; //拼接完整的485数据
//print("显示485数据:".$complete."\n");
$encryption = base64_encode(hex2bin(strtoupper($complete))); //base64加密
return $encryption;
}
public function crc16($string, $length = 0)
{
$auchCRCHi = array(
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40
);
$auchCRCLo = array(
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4,
0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD,
0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7,
0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE,
0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2,
0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB,
0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91,
0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88,
0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80,
0x40
);
$length = ($length <= 0 ? strlen($string) : $length);
$uchCRCHi = 0xFF;
$uchCRCLo = 0xFF;
$uIndex = 0;
for ($i = 0; $i < $length; $i++) {
$uIndex = $uchCRCLo ^ ord(substr($string, $i, 1));
$uchCRCLo = $uchCRCHi ^ $auchCRCHi[$uIndex];
$uchCRCHi = $auchCRCLo[$uIndex];
}
return (chr($uchCRCLo) . chr($uchCRCHi));
}
public function setSecretKey1($initKey)
{
$initKeyArr = str_split($initKey, 2);
$newKey = 0;
for ($k = 0; $k < count($initKeyArr); $k++) {
$newKey ^= hexdec($initKeyArr[$k]);
}
$tmpOneKey = dechex($newKey);
return $tmpOneKey;
}
}
这一块代码,每个硬件厂商可能都不一样。本质都是一样的。