这个功能很实用。
本小区的人,自动进入。并可以记录下通行记录,以及老人进入情况。
还支持二维码进入,访客进入。
只要建好数据表,做好实名认证,做好数据记录就可以了。

<?php


namespace Face\Func;

/**
 * 响应类
 * 局部使用
 */
class Respond
{
    private $attr = array();
    /**
     * 消息输出字节大小,API调用统计使用
     *
     * @var int
     */
    private $output_bytes = 0;
    public function __construct()
    {
        $this->attr['code']     = 0;
        $this->attr['description']   = "";
        $this->attr['result'] = null;
    }

    public function setErr($code, $description)
    {
        $this->attr['code']   = (int)$code;
        $this->attr['description'] = $description;
    }

    /**
     * 增加一个属性
     * @param string $name 属性名
     * @param mixed $value 属性值
     */
    public function setAttr($name, $value)
    {
        $this->attr[$name] = $value;
    }


    public function getAttr($name)
    {
        return $this->attr[$name];
    }

    /**
     * 删除一个属性
     * @param string $name 属性名
     */
    public function removeAttr($name)
    {
        if (isset($this->attr[$name])) {
            unset($this->attr[$name]);
        }
    }

    public function Send($key = 'fbe47880b9171706')
    {
        $data = json_encode($this->attr,JSON_UNESCAPED_UNICODE);
        $encrypt = openssl_encrypt($data, 'AES-128-ECB', $key, 0);
        // 务必加一层 data 层,否则机器识别不了
        echo json_encode(['data' => $encrypt]);
        exit;
    }

    /**
     * 输出json
     * @param string $description
     * @param int $code
     */
    public function err($description = 'Err', $code = -1)
    {
        $this->setErr($code, $description);
        $this->Send();
    }


    /**
     * 输出json
     * @param array $out_data
     * @param string $description
     * @param bool $force_out 强制展示结果
     */
    public function ok($out_data = [], $description = 'OK', $force_out = false)
    {
        $this->setErr(0, $description);
        if ($out_data || $force_out) {
            $this->setAttr('result', $out_data !== null ? $out_data : []); // null的时候返回空
        }
        $this->Send();
    }
}

业务接口

<?php


/**
 * 人脸识别相关接口
 * 第一步,登录 login
 * 第二步,获取配置时间 serverConfig_time
 * 第三步,根据配置时间,获取变动的信息 广告、公司、配置、组等信息,其中group组信息最关键
 * 第四步,根据组,获取组员信息group_info 
 * 第五步,根据组员信息,更新组员图片【图片id】等信息 group_user
 * 第六步,根据图片id,上传图片【图片变更,才会上传。或者初始化的时候,才会上传】image_download
 * 第七步,进出的时候,会调用image_upload。这个可以通过配置来控制。
 * 第八步,如果没有图片上传,将直接调用record。将出行记录存入数据库。
 * 如果是通过二维码访问,将调用qrCode接口。
 * 这些硬件里,有业务流程,定义好接口名称,它将会调用你写的接口。根据你提供的数据返回,做出下一步的反应。
 */

namespace Face\Action;

class AlfAction extends CommonAction
{
    protected $key;
    public function _initialize()
    {
        parent::_initialize();
        $this->key = 'fbe47880b9171706';
    }

    /**
     * 登录 开机第一步,先login
     */
    public function login() {
        $in_data = $this->decrypt_data();
        
        $out_data = [];
        $out_data['key'] = '12345678';
        $out_data['token'] = 'A4105F8A24A591BA1EEA12B2CD1FF648';
        $out_data['AESPassWord'] = 'fbe47880b9171706';
        // setlog($in_data,$out_data,'login');

        $this->respond->ok($out_data);
    }

    /**
     * 时间,最最频繁的接口
     */
    public function serverConfig_time() {
        $in_data = $this->decrypt_data();

        // 更新设备状态
        $sn = $in_data['deviceSn'];
        $device = M('device');
        $save_data = [];
        $save_data['online'] = 1;
        $save_data['update_time'] = date('Y-m-d H:i:s');
        $device->where(['device_type'=>1,'mac_address'=>$sn])->save($save_data);

        $out_data = [];
        $out_data['configUpTime'] = time()*1000;
        $out_data['groupUpTime'] = time()*1000;
        $out_data['companyUpTime'] = time()*1000;
        $out_data['advertisingTime'] = time()*1000;
        // setlog($in_data,$out_data,'serverConfig_time');
        $this->respond->ok($out_data);
    }

    /**
     * 获取配置信息
     */
    public function config() {
        $in_data = $this->decrypt_data();
        $out_data = [];

        $sn = $in_data['deviceSn'];
        $device = M('device');
        $device_info = $device->where(['mac_address'=>$sn,'device_type'=>1])->find();
        $out_data = [
            'deviceSn' =>$sn,
            'deviceName' =>$device_info['name'],
            'thirdComparisonMode' => 7, // 人脸或二维码
            'oneOne' => "0.61", 
            'oneN' => "0.81", 
            'livenessSwitch' => 0, 
            'runMode' => 0, 
            'flashMode' => 2, 
            'standyInterval' => 2, 
            'thirdAddress' => 9090, 
            'autoReboot' => 1, 
            'rebootInterval' => 4, 
            'setRebootTime' => "23:58", 
            'upAvatar' => 0, 
            'upBgFlag' => 0, 
            'updateTime' => time() * 1000, 
            'inOut' => 0, 
            'requestInterval' => 90, 
            'adminPassWord' =>  md5('888888'), 
            'qrCodeSwitch' =>  true, 
        ];

        // setlog($in_data,$out_data,'config');
        $this->respond->ok($out_data);
    }

    /**
     * 通过设备SN号获取用户组列表
     * 通过传入设备的 SN 号,以获取所有的用户组列表。
     */
    public function group() {
        $in_data = $this->decrypt_data();
        $sn = $in_data['deviceSn'];
        $device = M('device');
        $device_info = $device->where(['mac_address'=>$sn,'device_type'=>1])->find();
        if (!$device_info) {
            $this->respond->err('设备不存在');
        }

        $village_id = $device_info['village_id'];

        $village = M('village');
        $village_info = $village->where(['id'=>$village_id])->find();

        // 更新时间很重要,足够大,才会去更新数据
        $out_data[] = [
            'groupId' => $village_info['id'],
            'updatedAt' => time()*1000,//strtotime($village_info['update_time']) * 1000,
            'groupName' => $village_info['name'],
            'createdAt' => strtotime($village_info['create_time']) * 1000
        ];

        // setlog($in_data,$out_data,'group');
        $this->respond->ok($out_data);
    }

    /**
     * 获取组内用户列表
     */
    public function group_info() {
        $in_data = $this->decrypt_data();
        $out_data = [];

        $village_id = $in_data['groupId'];
        $user_customer_village = M('user_customer_village');

        // 去重获取用户信息
        $customer_ids = $user_customer_village->where(['village_id'=>$village_id,'customer_id'=>['gt',0]])->distinct(true)->getField('customer_id',true);
        
        // 获取业主信息
        $user_customer = M('user_customer');
        $user_customer_list = $user_customer->where(['id'=>['in',$customer_ids]])->field('id,create_time,update_time')->select();

        // 更新时间很重要,足够大,才会去更新group_user
        foreach($user_customer_list as  $k => $v) {
            $out_data[] = [
                'userId' => (int)$v['id'],
                'createdAt' => strtotime($v['create_time']) * 1000,
                'updatedAt' => time()*1000, // strtotime($v['update_time']) * 1000,
                'groupId' => (int)$village_id,
            ];
        }

        // setlog($in_data,$out_data,'group_info');
        $this->respond->ok($out_data);
    }

    /**
     * 获取用户信息,先不考虑访客
     */
    public function group_user() {
        $in_data = $this->decrypt_data();
        $out_data = [];

        $village_id = $in_data['groupId'];
        $customerIds = $in_data['userIds'];

        $village = M('village');
        $village_info = $village->where(['id'=>$village_id])->find();
        $groupName = $village_info['name'];

        // 获取用户列表
        $user_customer = M('user_customer');
        $user_customer_list = $user_customer->where(['id'=>['in',$customerIds]])->select();

        $user_customer_village = M('user_customer_village');
        $user_customer_image = M('user_customer_image');

        // avatarId 变更后,才会去调用图片
        foreach($user_customer_list as  $k => $v) {
            $qr_content = $user_customer_village->where(['customer_id'=>$v['id'],'village_id'=>$village_id])->getField('qr_content');
            $avatarId = $user_customer_image->where(['customer_id'=>$v['id']])->order('id desc')->getField('id');
            $out_data[] = [
                'icNumber' => $qr_content,
                'birthDay' => "1995-08-27",
                "modelVersion" => "local",
                "idNumber" => $v['idcard'],
                'companyId' => 1,
                'createdAt' => strtotime($v['create_time']) * 1000,
                'userUpdatedAt' => time()*1000, // strtotime($v['update_time']) * 1000,
                'permission' => 1,
                'avatarId' => (string)$avatarId,
                'type' => 1,
                'artAvatar' => 1,
                // 'feature' => "",
                'userId' => (string)$v['id'],
                'prompt' => "",
                'groupId' => (int)$village_id,
                'groupName' => $groupName,
                'userName' => $v['name'],
            ];
        }

        // setlog($in_data,$out_data,'group_user');
        $this->respond->ok($out_data);
    }

    /**
     * 获取图片
     */
    public function image_download() {
        $in_data = $this->decrypt_data();
        $out_data = [];

        // 获取头像id
        $avatarId = $in_data['avatarId'];

        $user_customer_image = M('user_customer_image');
        $user_customer_image_info = $user_customer_image->where(['id'=>$avatarId])->find();
        $img_url = $user_customer_image_info['original_url'];

        $out_data = $img_url;
        // setlog($in_data,$out_data,'image_download');

        // 返回图片
        //声明需要创建的图层的图片格式
        header("Content-Type:image/png");
        
        echo file_get_contents($img_url);
        // $this->respond->ok($out_data);
    }

    /**
     * 上传图片 这个功能暂时不需要
     */
    public function image_upload() {
        $in_data = $this->decrypt_data();
        $out_data = [];

        setlog($in_data,$out_data,'image_upload');
        $this->respond->ok($out_data);
    }

    /**
     * 上传打卡记录
     */
    public function record() {
        $in_data = $this->decrypt_data();
        $out_data = [];

        $groupId = $in_data['groupId'];
        $userId = $in_data['userId'];
        $sn = $in_data['deviceSn'];

        $device = M('device');
        $device_info = $device->where(['mac_address'=>$sn,'device_type'=>1])->find();
        if (!$device_info) {
            $this->respond->err('设备不存在');
        }
        $record_add_data = [];
        $record_add_data['village_id'] = $groupId;
        $record_add_data['device_id'] = $device_info['id'];
        $record_add_data['user_id'] = $userId;
        $record_add_data['create_time'] = date('Y-m-d H:i:s');
        $record_add_data['device_sn'] = $sn;
        $record_add_data['type'] = 1;
        $record_add_data['user_type'] = 0;
        $record_add_data['walk_type'] = 0;
        // 判断是否是老人
        $user_customer = M('user_customer');
        $user_customer_info = $user_customer->where(['id'=>$userId])->find();
        if (!$user_customer_info) {
            $this->respond->err('用户不存在');
        }

        if ($user_customer_info['age'] >= 60) {
            // 增加message
            $message_add_data = [];
            $message_add_data['message'] = "老人:".$user_customer_info['name']."在:".date('Y-m-d H:i:s')."出门了";
            $message_add_data['create_time'] = date('Y-m-d H:i:s');
            $message = M('message');
            $message->add($message_add_data);

            $record_add_data['is_old'] = 1;
        } else {
            $record_add_data['is_old'] = 0;
        }

        // TODO 插入redis,用于websocket
        $user_record = M('user_record');
        $user_record->add($record_add_data);

        // 无数据返回
        setlog($in_data,$out_data,'record');
        $this->respond->ok($out_data);
    }

    /**
     * 上传异常信息
     */
    public function feedback() {
        $in_data = $this->decrypt_data();
        $out_data = [];

        setlog($in_data,$out_data,'feedback');
        $this->respond->ok($out_data);
    }

    /**
     * 添加人员
     */
    public function add_staff() {
        $in_data = $this->decrypt_data();
        $out_data = [];

        setlog($in_data,$out_data,'add_staff');
        $this->respond->ok($out_data);
    }

    /**
     * 公司相关信息
     */
    public function company_config() {
        $in_data = $this->decrypt_data();

        $out_data = [];
        $out_data['companyId'] = '1';
        // 毫秒时间戳
        $out_data['createAt'] = '1557884520000';
        $out_data['companyName'] = 'xxx';
        $out_data['companyLogUrl'] = '';

        // setlog($in_data,$out_data,'company_config');
        $this->respond->ok($out_data);
    }

    /**
     * 第三方比对
     */
    public function thislocality() {
        $in_data = $this->decrypt_data();
        $out_data = [];

        setlog($in_data,$out_data,'thislocality');
        $this->respond->ok($out_data);
    }

    /**
     * 下载广告图片
     */
    public function advertising() {
        $in_data = $this->decrypt_data();
        $out_data = [];

        setlog($in_data,$out_data,'advertising');
        $this->respond->ok($out_data);
    }

    /**
     * 检查版本号
     */
    public function checkVersion() {
        $in_data = $this->decrypt_data();
        $out_data = [];

        setlog($in_data,$out_data,'checkVersion');
        $this->respond->ok($out_data);
    }

    /** 
     * 二维码 上传二维码接口 用于后台校验二维码使用
     */
    public function qrCode() {
        $in_data = $this->decrypt_data();
        $out_data = [];

        $sn = $in_data['deviceSn'];
        $qrNumber = $in_data['qrNumber'];

        // 访客或者业主
        $userId = 0;
        $validQrCode = false;

        $device = M('device');
        $user_customer_village = M('user_customer_village');
        $customer_visitor = M('customer_visitor');
        $user_record = M('user_record');
        $device_info = $device->where(['mac_address'=>$sn,'device_type'=>1])->find();


        if ($qrNumber) {
            $where['_query'] = 'qr_content='.$qrNumber.'&qr_content_new='.$qrNumber.'&_logic=or';
            $where['village_id'] = $device_info['village_id'];
            $user_customer_village_info = $user_customer_village->where($where)->order('update_time desc')->find();
            if ($user_customer_village_info) { // 业主
                $userId = $user_customer_village_info['customer_id'];
                $validQrCode= true;

                $record_add_data = [
                    'user_id' => $userId,
                    'device_id' => $sn,
                    'village_id' => $device_info['village_id'],
                    'create_time' => date('Y-m-d H:i:s'),
                    'device_sn' => $sn,
                    'type' => 1,
                    'user_type' => 0,
                    'walk_type' => 1
                ];
                $user_record->add($record_add_data);
            } else { // 访客
                $customer_visitor_info = $customer_visitor->where(['qr_content'=>$qrNumber,'village_id'=>$device_info['village_id'],'visit_date'=>['like',date('Y-m-d').'%']])->find();
                if ($customer_visitor_info) { // 访客
                    $validQrCode= true;
                    $record_add_data = [
                        'user_id' => $customer_visitor_info['id'] + 500000,
                        'device_id' => $sn,
                        'village_id' => $device_info['village_id'],
                        'create_time' => date('Y-m-d H:i:s'),
                        'device_sn' => $sn,
                        'type' => 1,
                        'user_type' => 1,
                        'walk_type' => 1
                    ];
                    $user_record->add($record_add_data);
                }
            }
        }

        $out_data = [
            'userId' => $userId,  // 用于显示是哪个用户,如果id存在,就不看后面validQrCode了。如果id是0,则会看后面的是否为true。
            'validQrCode' => $validQrCode,
        ];

        setlog($in_data,$out_data,'qrCode');
        $this->respond->ok($out_data);
    }

    /**
     * 解析数据
     */
    protected function decrypt_data() {
        $in_data = $_POST;
        $encrypt_data = $in_data['data'];
        // 解码数据
        $data = openssl_decrypt($encrypt_data, 'AES-128-ECB', $this->key , 0);
        $data = json_decode($data,true);
        return $data;
    }
}