一、前言说明
这个项目很多年前就完成的,属于一个定制的项目,最初做的事楼宇对讲相关的功能,后面陆续增加了门禁和视频监控,这些模块加起来,慢慢的形成了一个智能安防集中管理平台的模样,但是确切的说又不够标准,因为本系统楼宇对讲部分,并不包含对讲的功能,而是楼宇对讲门禁系统将下面的状态发过来,在软件端展示,比如对讲状态,谁正在呼叫谁,哪里的门禁开启和关闭了,然后具备制作门禁卡的功能,其实就是通过USB的写入和读取,按照协议将卡的数据读取,然后下发到门禁设备,让门禁设备知道当前哪些卡是合法的卡,该卡刷完后会立即通知软件端,软件端这边已经关联了具体哪一户人家,然后记录存档以供查询。
视频监控这块复用的视频监控组件的功能,比较简单,主要就是添加视频流地址,然后显示视频流画面,然后就是还多了个报警联动功能,一旦某个地方触发了报警,可以打开对应的联动视频显示。如果需要更详细的视频监控功能,推荐使用视频监控系统,非常的全面和完善。
二、效果图
三、功能特点
- 同时集成了楼宇对讲、住户报警、门禁控制、公共报警、视频监控等模块。
- 系统管理部分包括系统配置、对讲配置、住户配置、公共配置、监控配置、地图管理、视频联动、用户管理、区域管理。
- 图形化的实时对讲、室内报警、门禁设备界面,非常大气美观。
- 设备状态内置地图模式、面板模式两种方式展示,非常强大。
- 楼宇对讲设备和报警设备都支持地图上拖曳到正确位置,保存立即应用。
- 支持报警视频联动,设备报警对应弹出报警视频。
- 各种设备信息支持添加、删除、修改、打印、导入、导出、查询等,支持多条件组合查询。
- 各种日志信息支持多条件组合模糊查询,查询的记录可导出和打印。
- 可直接在软件上授权发卡,支持多对多发卡,一个卡号可以发到多个门禁设备,支持通卡(卡号下发到所有设备),可连续自动制卡,自动选中下一个用户进行制卡。
- 可直接远程读取选中设备的卡号集合信息,进行统一的管理。
- 所有卡号支持本地备份,一旦远程设备更换,可以重新下发卡号信息。
- 支持过期卡号自动清理,被清理的卡号可以查询,可以指定楼栋、单元、过期时间查询卡号。
- 支持公共部位报警接入,默认DS7400主机,能够识别布防、撤防、报警等信息。
- 视频监控默认支持16通道显示,可切换到4通道、6通道、8通道、9通道、13通道显示,支持全屏和轮询。
- 首页背景图、左上角logo、右上角项目名称可自定义,支持恢复出厂设置。
- 亿级别本地海量数据存储,自动清空早期数据,永远保持最新的数据记录。
- 每个模块都有开关可以后台自由控制启用或者禁用。
- 集成了秘钥控制功能,可以控制设备数量以及运行时间。
- 内置最牛逼的豪华版的输入法,高仿苹果电脑输入法,体验一级棒。
- 纯Qt编写,支持任意Qt版本+任意编译器+任意系统,可运行在windws XP、win7、win8、win10、linux、mac OS、嵌入式linux等系统。
四、相关地址
- 国内站点:https://gitee.com/feiyangqingyun
- 国际站点:https://github.com/feiyangqingyun
- 个人作品:https://blog.csdn.net/feiyangqingyun/article/details/97565652
- 文件地址:https://pan.baidu.com/s/1d7TH_GEYl5nOecuNlWJJ7g 提取码:01jf 文件名:bin_TB.zip。
五、相关代码
#include "taskserver.h"
#include "qthelper.h"
#include "ntpclient.h"SINGLETON_IMPL(TaskServer)
TaskServer::TaskServer(QObject *parent) : QObject(parent)
{checkNtpCount = 0;timerTask = new QTimer(this);timerTask->setInterval(3000);connect(timerTask, SIGNAL(timeout()), this, SLOT(checkTask()));timerDefence = new QTimer(this);timerDefence->setInterval(1000);connect(timerDefence, SIGNAL(timeout()), this, SLOT(checkDefence()));timerSize = new QTimer(this);timerSize->setInterval(60 * 1000);connect(timerSize, SIGNAL(timeout()), this, SLOT(checkSize()));process = new QProcess(this);connect(process, SIGNAL(readyRead()), this, SLOT(readData()));
}TaskServer::~TaskServer()
{this->stop();
}void TaskServer::checkTask()
{//当开启Ntp校时,且还未超过校对次数,且当前年份小于2016,则重新校时if (AppConfig::UseNtp && checkNtpCount < 10 && QDate::currentDate().year() < 2017) {NtpClient::Instance()->getDateTime();checkNtpCount++;}int count = DbData::TaskInfo_Action.count();for (int i = 0; i < count; ++i) {QString action = DbData::TaskInfo_Action.at(i);QString subsystem = DbData::TaskInfo_Subsystem.at(i);QString triggerTime = DbData::TaskInfo_TriggerTime.at(i);if (!taskDo.contains(action)) {QTime old = QTime::fromString(triggerTime, "HH:mm:ss");QTime now = QTime::currentTime();qint64 timeout = old.secsTo(now);int offset = 5;if (timeout >= 0 && timeout < offset) {//重启命令定位精准即时重启,规定秒之内才重启一次if (action == "重启") {qDebug() << TIMEMS << "timeout restart";appendAction(action);
#ifdef Q_OS_ARMAppFun::reboot();
#endif}} else if (timeout >= offset) {int subSystem = subsystem.right(1).toInt();if (action == "布防") {appendAction(action);//API::deviceArmingBySub(subSystem);} else if (action == "撤防") {appendAction(action);//API::deviceDisarmingBySub(subSystem);} else if (action == "故障旁路") {appendAction(action);//API::deviceBypassBySub(subSystem);}}}}
}void TaskServer::checkDefence()
{int count = DbData::DelayDefence.count();for (int i = 0; i < count; ++i) {QStringList list = DbData::DelayDefence.at(i).split("|");QString type = list.at(0);if (type == "Arming") {//取出布防的时间,将超过时间的任务移除QString time = list.at(2);QDateTime old = QDateTime::fromString(time, "yyyy-MM-dd HH:mm:ss");QDateTime now = QDateTime::currentDateTime();if (old.secsTo(now) >= AppConfig::DelayTimeArming) {qDebug() << TIMEMS << "remove task" << list;DbData::DelayDefence.removeAt(i);break;}}}
}void TaskServer::checkSize()
{
#ifndef __arm__return;
#endifprocess->start("df", QStringList() << "-h");
}void TaskServer::readData()
{while (!process->atEnd()) {QString result = QLatin1String(process->readLine());if (result.startsWith("/dev/")) {QString dev, use, free, all;int percent = 0;QStringList list = result.split(" ");int index = 0;for (int i = 0; i < list.count(); ++i) {QString s = list.at(i).trimmed();if (s == "") {continue;}index++;if (index == 1) {dev = s;} else if (index == 2) {all = s;} else if (index == 3) {use = s;} else if (index == 4) {free = s;} else if (index == 5) {percent = s.left(s.length() - 1).toInt();break;}}if (all.endsWith("G")) {AppData::IsFullSize = (percent > 100);}}}
}void TaskServer::appendAction(const QString &action)
{taskDo.append(action);QtHelper::writeInfo("自动执行任务: " + action);
}void TaskServer::start()
{timerTask->start();timerDefence->start();timerSize->start();
}void TaskServer::stop()
{timerTask->stop();timerDefence->stop();timerSize->stop();
}bool TaskServer::existTaskDefence(const QString &type, const QString &value)
{bool exist = false;int count = DbData::DelayDefence.count();for (int i = 0; i < count; ++i) {QStringList list = DbData::DelayDefence.at(i).split("|");QString currentType = list.at(0);QString currentValue = list.at(1);if (currentType == type) {//如果长度为0则说明是全部布防或者子系统布防if (type == "Arming" && currentValue.length() == 1) {exist = true;} else if (currentValue == value) {currentValue == value;}break;}}return exist;
}void TaskServer::appendErrorDefenceID(const QString &defenceID)
{if (!errorDefenceID.contains(defenceID)) {errorDefenceID.append(defenceID);}
}void TaskServer::removeErrorDefenceID(const QString &defenceID)
{errorDefenceID.removeOne(defenceID);
}void TaskServer::clearErrorDefenceID(const QString &defenceID)
{int busStatusCount = DbData::BusStatus.count();//DbData::BusStatus 存储含义 防区号|设备地址|设备索引|防区状态(0-正常,1-报警,3-离线)|左防区攀爬报警|右防区攀爬报警|是否校验过离线|最后一次消息时间for (int i = 0; i < busStatusCount; ++i) {QStringList list = DbData::BusStatus.at(i).split("|");QString strDefenceID = list.at(0);quint8 addr = list.at(1).toInt();quint8 index = list.at(2).toInt();//将当前防区重置为正常状态if (strDefenceID == defenceID) {QString strStatus = QString("%1|%2|%3|%4|%5|%6|%7|%8").arg(defenceID).arg(addr).arg(index).arg(0).arg(0).arg(0).arg(0).arg(DATETIME);DbData::BusStatus[i] = strStatus;break;}}
}void TaskServer::clearErrorDefenceID()
{int busStatusCount = DbData::BusStatus.count();//DbData::BusStatus 存储含义 防区号|设备地址|设备索引|防区状态(0-正常,1-报警,3-离线)|左防区攀爬报警|右防区攀爬报警|是否校验过离线|最后一次消息时间for (int i = 0; i < busStatusCount; ++i) {QStringList list = DbData::BusStatus.at(i).split("|");QString defenceID = list.at(0);quint8 addr = list.at(1).toInt();quint8 index = list.at(2).toInt();//重置为正常状态QString strStatus = QString("%1|%2|%3|%4|%5|%6|%7|%8").arg(defenceID).arg(addr).arg(index).arg(0).arg(0).arg(0).arg(0).arg(DATETIME);DbData::BusStatus[i] = strStatus;}
}void TaskServer::changeError()
{int busStatusCount = DbData::BusStatus.count();//DbData::BusStatus 存储含义 防区号|设备地址|设备索引|防区状态(0-正常,1-报警,3-离线)|左防区攀爬报警|右防区攀爬报警|是否校验过离线|最后一次消息时间for (int i = 0; i < busStatusCount; ++i) {QStringList list = DbData::BusStatus.at(i).split("|");QString defenceID = list.at(0);if (errorDefenceID.contains(defenceID)) {quint8 addr = list.at(1).toInt();quint8 index = list.at(2).toInt();//重置为故障状态QString strStatus = QString("%1|%2|%3|%4|%5|%6|%7|%8").arg(defenceID).arg(addr).arg(index).arg(1).arg(0).arg(0).arg(0).arg(DATETIME);DbData::BusStatus[i] = strStatus;}}
}void TaskServer::changeStatus()
{int busStatusCount = DbData::BusStatus.count();//DbData::BusStatus 存储含义 防区号|设备地址|设备索引|防区状态(0-正常,1-报警,3-离线)|左防区攀爬报警|右防区攀爬报警|是否校验过离线|最后一次消息时间for (int i = 0; i < busStatusCount; ++i) {QStringList list = DbData::BusStatus.at(i).split("|");QString defenceID = list.at(0);quint8 addr = list.at(1).toInt();quint8 index = list.at(2).toInt();quint8 leftDragAlarm = list.at(4).toInt();quint8 rightDragAlarm = list.at(5).toInt();quint8 isCheck = list.at(6).toInt();//故障防区链表中的防区需要置为故障quint8 status = errorDefenceID.contains(defenceID) ? 1 : 0;QString strStatus = QString("%1|%2|%3|%4|%5|%6|%7|%8").arg(defenceID).arg(addr).arg(index).arg(status).arg(leftDragAlarm).arg(rightDragAlarm).arg(isCheck).arg(DATETIME);DbData::BusStatus[i] = strStatus;}
}