## 一、前言说明
这个项目很多年前就完成的,属于一个定制的项目,最初做的事楼宇对讲相关的功能,后面陆续增加了门禁和视频监控,这些模块加起来,慢慢的形成了一个智能安防集中管理平台的模样,但是确切的说又不够标准,因为本系统楼宇对讲部分,并不包含对讲的功能,而是楼宇对讲门禁系统将下面的状态发过来,在软件端展示,比如对讲状态,谁正在呼叫谁,哪里的门禁开启和关闭了,然后具备制作门禁卡的功能,其实就是通过USB的写入和读取,按照协议将卡的
数据读取,然后下发到门禁设备,让门禁设备知道当前哪些卡是合法的卡,该卡刷完后会立即通知软件端,软件端这边已经关联了具体哪一户人家,然后记录存档以供查询。
视频监控这块复用的视频监控组件的功能,比较简单,主要就是添加视频流地址,然后
显示视频流画面,然后就是还多了个报警联动功能,一旦某个地方触发了报警,可以打开对应的联动视频显示。如果需要更详细的视频监控功能,推荐使用视频监控系统,非常的全面和完善。
## 二、效果图





## 三、功能特点
1. 同时集成了楼宇对讲、住户报警、门禁控制、公共报警、视频监控等模块。
2. 系统管理部分包括系统配置、对讲配置、住户配置、公共配置、监控配置、地图管理、视频联动、用户管理、区域管理。
3.
图形化的实时对讲、室内报警、门禁设备
界面,非常大气美观。
4. 设备状态内置地图模式、面板模式两种方式展示,非常强大。
5. 楼宇对讲设备和报警设备都支持地图上拖曳到正确位置,保存立即应用。
6. 支持报警视频联动,设备报警对应弹出报警视频。
7. 各种设备信息支持添加、删除、修改、打印、导入、导出、查询等,支持多条件组合查询。
8. 各种日志信息支持多条件组合模糊查询,查询的记录可导出和打印。
9. 可直接在软件上授权发卡,支持多对多发卡,一个卡号可以发到多个门禁设备,支持通卡(卡号下发到所有设备),可连续自动制卡,自动选中下一个用户进行制卡。
10. 可直接远程读取选中设备的卡号集合信息,进行统一的管理。
11. 所有卡号支持本地备份,一旦远程设备更换,可以重新下发卡号信息。
12. 支持过期卡号自动清理,被清理的卡号可以查询,可以指定楼栋、单元、过期时间查询卡号。
13. 支持公共部位报警接入,默认DS7400主机,能够识别布防、撤防、报警等信息。
14. 视频监控默认支持16通道显示,可切换到4通道、6通道、8通道、9通道、13通道显示,支持全屏和轮询。
15. 首页背景图、左上角logo、右上角项目名称可自定义,支持恢复出厂设置。
16. 亿级别本地海量数据存储,自动清空早期数据,永远保持最新的数据记录。
17. 每个模块都有开关可以后台自由控制启用或者禁用。
18. 集成了秘钥控制功能,可以控制设备数量以及运行时间。
19. 内置最牛逼的豪华版的输入法,高仿苹果电脑输入法,体验一级棒。
20. 纯Qt编写,支持任意Qt版本+任意
编译器+任意系统,可运行在windws XP、win7、win8、win10、linux、mac OS、嵌入式linux等系统。
## 四、相关地址
1. 国内站点:[
https://gitee.com/feiyangqingyun](https://gitee.com/feiyangqingyun)
2. 国际站点:[
https://github.com/feiyangqingyun](https://github.com/feiyangqingyun)
3. 个人作品:[
https://blog.csdn.net/feiyangqingyun/article/details/97565652](https://blog.csdn.net/feiyangqingyun/article/details/97565652)
4.
文件地址:[
https://pan.baidu.com/s/1d7TH_GEYl5nOecuNlWJJ7g](https://pan.baidu.com/s/1d7TH_GEYl5nOecuNlWJJ7g) 提取码:01jf 文件名:bin_TB.zip。
## 五、相关代码
```cpp
#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_ARM
AppFun::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;
#endif
process->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
= 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 = 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 = 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 = strStatus;
}
}
```