C#实现完整的防盗自制监控系统
在您的手机中通知您家中的入侵者,并拍摄他们的照片
介绍
在本文中,我将展示一些DIY东西,用于安装监控系统,检测家中的入侵者,拍摄照片并通过手机通知您,必要时可以打电话给警察并提供照片以便快速识别劫匪,并提高你恢复所有被盗事物的机会。
当然,除了这个软件,你必须提供一些硬件,但我已经在我家使用相对便宜的材料建造了这个系统,如果我们除了相机,这是安装中最昂贵的部分。但你可以用相机做很多事情,所以它可以是一个好的和有趣的投资。
基本上,这是系统架构,包含所有参与元素:
虽然在模式中我已经代表了一些具体的子系统,但实际上我已经设计了解决方案,以便通过实现公共接口并使用依赖注入将它们与应用程序链接,可以独立开发所有这些元素。不同的子系统或协议如下:
- 摄像机协议:定义与摄像机的通信。
- 存储协议:定义文件传输,图像和控制命令/响应。
- 触发协议:启动监控系统。
- 警报协议:将事件远程传达给用户。
该解决方案使用Visual Studio 2015和4.5版的.Net Framework实现。
你可以在我的博客中找到这篇文章的更长版本网站源码,这里有西班牙文版本。由于此站点的文件大小限制为10MB,我不得不删除源代码中的大量文件,所有NuGet包,obj目录和所有二进制文件。虽然您可以从Visual Studio还原包,但您可能无法重新编译代码。在这种情况下,您可以从我的网站,在上一个链接中下载项目的完整文件集。
硬件
让我们回顾一下我用来构建系统的硬件。由于应用程序可以通过多种方式进行扩展,因此您可以使用自己的不同硬件选择来安装它。
首先是相机。我有两个IP摄像头,每个都有不同的协议。更便宜的是一个概念性的wifi摄像头,价格约50€和协议NetWave cgi。另一种是专业的,具有高性能,但也是非常高的价格。这是一款采用VAPIX cgi协议的Axis相机。
为了拨打移动电话,我买了一个简单的USB AT调制解调器,价格约为17欧元:
当然,作为触发器,我使用的是Arduino板(约20欧元),存在探测器开关(约10欧元)和继电器。由于存在开关适用于220V,因此将其直接连接到Arduino板是一个坏主意。因此,我已将探测器连接到12V电源,并将继电器的电源连接到另一个开关,该电源关闭5V Arduino电源和输入引脚之间的电路。这完全隔离了220V主电源的Arduino板(以及计算机)。
你可以轻松地建立一个继电器电路。只需将12个电源连接到继电器卷轴,将二极管从地线连接到12V电线,然后从Arduino侧使用输入引脚(PI)作为触发引脚,输出引脚(PO)用力电路开路时输入引脚为0V,5V电源信号激活输入引脚:
这是Arduino代码,我使用引脚28作为输入,24使用输出,因为在Arduino Mega板中它们靠近5V引脚,但是你可以使用你想要的,当然。
int pin1 = 28;
int pin0 = 24;
void setup() {
// Initialize pins
pinMode(pin0, OUTPUT);
digitalWrite(pin0, LOW);
pinMode(pin1, INPUT);
digitalWrite(pin1, LOW);
Serial.begin(9600);
}
void loop() {
int val = digitalRead(pin1);
if (val == HIGH) {
Serial.write(1);
}
delay(1000);
}
最后,虽然这不是真正的硬件,但我会提到我使用过的存储协议。我选择Dropbox作为将照片上传到云端的最简单,最便宜的方式,我还使用此媒体将移动客户端与控制中心进行通信,使用带有JSON格式数据的文本文件。
控制中心
在ThiefWatcher项目中,实现了中央控制应用程序。它是一个桌面MDI Windows应用程序,基本上有两种不同的窗口类型。其中一个是控制面板,您可以在其中设置所有协议,而不是摄像机:
顶部窗格用于触发器协议。在这里,您可以选择要使用的协议,提供具有相应设置的连接字符串(可以从协议到另一个不同),系统必须启动监视模式的开始日期/时间(如果您不提供,系统启动(中间),停止监视的结束日期/时间,您可以配置检测到入侵者时拍摄的照片数量和照片之间的秒数(整数)。
此窗格下方是通知(警报)协议。在下拉列表右侧选择协议,您有一个测试按钮,允许您测试此协议,而无需进行任何模拟。您还必须提供带参数设置的字符串连接,并在协议允许数据传输的情况下提供可选消息。
底部窗格用于存储协议。您有一个连接字符串来设置参数(如果有)和一个用于存储数据的容器名称,可以是本地文件夹,FTP文件夹,Azure blob容器名称等。
命令按钮从左到右依次为Start Simulacrum,它启动或停止系统,就像检测到入侵者一样,因此您可以测试摄像机和存储协议以及与客户端的通信。在此模式下,不考虑开始和结束日期。接下来,“ 开始”按钮启动或停止实际监控模式。相机形式中没有显示图像(假设没有人在场)。最后,“ 保存”按钮会在配置文件中写入更改。
在代码使用部分,我将评论我已实现的所有协议的连接字符串的参数。
关于摄像机协议,每个摄像机的配置都在摄像机窗口中执行,您可以使用File / New Camera ...菜单选项显示摄像机窗口。首先,您必须为要添加的摄像机选择正确的摄像机协议,然后,您必须提供连接数据,摄像机URL,用户名和密码。然后,你可以看到这样一个窗口:
工具栏左侧的第一个按钮用于更改访问设置,第二个按钮用于显示相机设置对话框,该对话框在相应的协议中实现。然后,您有一个启动按钮和其他停止相机的按钮,因此您可以在配置相机时观看图像。摄像机ID必须是唯一的并且是必需的,因为您将使用此ID从客户端选择摄像机。最后两个按钮用于将摄像机保存在配置文件中或将其删除。
所有这些设置都存储在应用程序 App.config文件中。connectionStrings部分中的连接字符串,appSettings部分中的其他协议设置。还有两个自定义部分用于存储协议列表以及不同的摄像机及其设置。
该cameraSection islike这样的:
<camerasSection>
<cameras>
<cameraData id="CAMNW"
protocolName="NetWave IP camera"
connectionStringName="CAMNW" />
<cameraData id="VAPIX"
protocolName="VAPIX IP Camera"
connectionStringName="VAPIX" />
</cameras>
</camerasSection>
每个照相机是一个cameraData元件,具有一个ID属性,protocolName与相应协议的名称属性,和一个的connectionStringName用于连接数据属性:URL,userName的和密码,存储在一个连接字符串中的ConnectionStrings部分。
还有一个protocolsSection,包含已安装协议的列表:
<protocolsSection>
<protocols>
<protocolData name="Arduino Simple Trigger"
class="trigger"
type="ArduinoSimpleTriggerProtocol.ArduinoTrigger, ArduinoSimpleTriggerProtocol, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<protocolData name="Lync Notifications"
class="alarm"
type="LyncProtocol.LyncAlarmChannel, LyncProtocol, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<protocolData name="AT Modem Notifications"
class="alarm"
type="ATModemProtocol.ATModemAlarmChannel, ATModemProtocol, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<protocolData name="Azure Blob Storage"
class="storage"
type="AzureBlobProtocol.AzureBlobManager, AzureBlobProtocol, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<protocolData name="NetWave IP camera"
class="camera"
type="NetWaveProtocol.NetWaveCamera, NetWaveProtocol, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<protocolData name="VAPIX IP Camera"
class="camera"
type="VAPIXProtocol.VAPIXCamera, VAPIXProtocol, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<protocolData name="DropBox Storage"
class="storage"
type="DropBoxProtocol.DropBoxStorage, DropBoxProtocol, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</protocols>
</protocolsSection>
每个协议有一个名字,一类,以确定它们的用法(触发,报警,存储或相机)和类型与所述完整的类型,其实现协议的类。
您可以使用File / Install Protocol / s ...菜单选项向此部分添加新协议,选择具有协议或协议实现的类库。
客户
无论您身在何处,应用程序都必须通知您可能的入侵,因此我将客户端实现为移动应用程序。几乎所有平台快速拥有应用程序版本的最简单方法是使用Xamarin来执行此操作,因此这是我选择的方法。
该TWClientApp PCL(便携式类库)项目包含在客户端几乎所有的代码。在不同平台的具体项目中,只有代码保存文件,将摄像头拍摄的照片保存在手机内存中,以便您尽快将其提供给警方。
这是我的第一个移动App项目,所以它不是很复杂。这里我没有使用依赖注入。相反,我只实现了Dropbox存储协议,因此,如果要使用另一个协议,则必须更改PCL库中的代码。此协议的优点是您可以使用Dropbox实际客户端获取照片,而无需使用ThiefWatcher客户端(尽管您失去了应用程序控制功能)。
启动客户端应用程序时,必须按“ 连接”按钮才能向主应用程序发送标识消息:
然后,将相机列表发送到客户端。您可以按相应的按钮选择其中一个:
您可以观看相机的当前图像。通常,您不能等待真正的视频流,因为上传每个图像可能会非常慢。中央控制实时获取帧,但Dropbox每上传花费最多两秒钟。
您可以使用按钮启动/停止相机,拍照或结束闹钟模式(在结束闹钟模式之前无需停止相机)。
照片显示在底部的列表中,您可以将其保存到手机或删除它们。
我无法测试iOS版本,因为我没有MAC,但Windows Phone和Android Apps工作正常。
使用代码
不同的协议接口在WatcherCommons项目的Interfaces名称空间中定义。摄像机协议是IWatcherCamera,定义如下:
public class FrameEventArgs : EventArgs
{
public FrameEventArgs(Bitmap bmp)
{
Image = bmp;
}
public Bitmap Image { get; private set; }
}
public delegate void NewFrameEventHandler(object sender, FrameEventArgs e);
public interface IWatcherCamera
{
event NewFrameEventHandler OnNewFrame;
Size FrameSize { get; }
string ConnectionString { get; set; }
string UserName { get; set; }
string Password { get; set; }
string Uri { get; set; }
int MaxFPS { get; set; }
bool Status { get; }
ICameraSetupManager SetupManager { get; }
void Initialize();
void ShowCameraConfiguration(Form parent);
void Start();
void Close();
}
- OnNewFrame:当图像准备好发送到应用程序时触发事件处理程序。图像在FrameEventArgs参数的Image属性中作为Bitmap传递。
- FrameSize:摄像机图像的当前宽度和高度。
- ConnectionString:用分号分隔的字符串,用于定义摄像机访问参数。在我实现的协议中,参数是url,userName和password,如下所示:url = http://192.168.1.20; userName = root; password = root。
- UserName,Password和Uri:与连接字符串中的相同。
- MaxFps:设置捕获率。
- 状态:如果摄像机正在运行,则为true。
- SetupManager:与摄像机设置对话框的界面。用于在用户更改摄像机图像大小时在应用程序中触发事件,以便可以正确调整摄像机表单的大小。
- 初始化:根据需要重置内部状态。
- ShowCameraConfiguration:显示摄像机配置对话框。它必须不是模态的,因此如果相机正在显示图像,您可以观察更改。
- 开始:开始图像捕获。这是在一个单独的线程中执行的,您必须在新帧事件中与相机交互时将其考虑在内。
- 停止:停止捕获。
该NetWave协议在实施NetWaveProtocol项目和VAPIX在协议VAPIXProtocol项目。
触发器协议ITrigger如下:
public interface ITrigger
{
event EventHandler OnTriggerFired;
string ConnectionString { get; set; }
void Initialize();
void Start();
void Stop();
}
- OnTriggerFired:在检测到触发条件时触发。
- ConnectionString:带有配置参数的字符串。在我已经实现的协议中,在ArduinoSimpleTriggerProtocol项目中,它们是端口和波特率,如下所示:port = COM4; baudrate = 9600。请记住在Arduino代码中设置相同的波特率。
- 初始化:根据需要重置intarnal状态。
- 开始:开始侦听触发条件。这是在一个单独的线程中完成的。
- 停止:停止听。
通知协议IAlarmChannel也很简单:
public interface IAlarmChannel
{
string ConnectionString { get; set; }
string MessageText { get; set; }
void Initialice();
void SendAlarm();
}
- ConnectionString:带有配置参数的字符串。
- MessageText:如果协议允许,则发送消息。
- 初始化:重置内部状态。
- SendAlarm:向客户端发送通知。
我实现的协议是ATModemProtocol项目,它使用AT调制解调器拨打一个或多个电话号码,并具有以下配置参数:
- port:连接调制解调器的COM端口。
- 波特率:设置端口波特率。
- initdelay:拨号前等待的延迟时间(以毫秒为单位)。
- number:逗号分隔的电话号码列表。
- ringduration:挂机前的时间,以毫秒为单位。
另一个协议使用Skype或Lync通知用户。它在LyncProtocol项目中实现。连接字符串是以分号分隔的Skype或Lync用户地址列表。您必须在主计算机和客户端上安装Lync客户端。
后者是存储协议,此协议使用的数据在WatcherCommons类库的Data命名空间中定义。有两个不同的类,ControlCommand用于摄像头命令:
[DataContract]
public class ControlCommand
{
public const int cmdGetCameraList = 1;
public const int cmdStopAlarm = 2;
public ControlCommand()
{
}
public static ControlCommand FromJSON(Stream s)
{
s.Position = 0;
StreamReader rdr = new StreamReader(s);
string str = rdr.ReadToEnd();
return JsonConvert.DeserializeObject<ControlCommand>(str);
}
public static void ToJSON(Stream s, ControlCommand cc)
{
s.Position = 0;
string js = JsonConvert.SerializeObject(cc);
StreamWriter wr = new StreamWriter(s);
wr.Write(js);
wr.Flush();
}
[DataMember]
public int Command { get; set; }
[DataMember]
public string ClientID { get; set; }
}
命令以JSON格式发送和接收。在Command成员中传递了两个不同的commnand,一个用于向应用程序注册并获取摄像机列表,另一个用于停止警报并将应用程序重置为监视模式。
该客户端ID构件唯一地标识每个客户端。
CameraInfo也是以JSON格式交换有关摄像机的请求和响应:
[DataContract]
public class CameraInfo
{
public CameraInfo()
{
}
public static List<CameraInfo> FromJSON(Stream s)
{
s.Position = 0;
StreamReader rdr = new StreamReader(s);
return JsonConvert.DeserializeObject<List<CameraInfo>>(rdr.ReadToEnd());
}
public static void ToJSON(Stream s, List<CameraInfo> ci)
{
s.Position = 0;
string js = JsonConvert.SerializeObject(ci);
StreamWriter wr = new StreamWriter(s);
wr.Write(js);
wr.Flush();
}
[DataMember]
public string ID { get; set; }
[DataMember]
public bool Active { get; set; }
[DataMember]
public bool Photo { get; set; }
[DataMember]
public int Width { get; set; }
[DataMember]
public int Height { get; set; }
[DataMember]
public string ClientID { get; set; }
}
- ID:摄像机标识符。
- 活动:相机状态。
- 照片:用于要求相机拍照。
- 宽度和高度:相机图像尺寸。
- ClientID:客户端唯一标识符。
当您请求摄像机列表时,您会收到一个带有一系列CameraInfo对象的响应,每个摄像机对应一个。
实现协议的接口是IStorageManager:
public interface IStorageManager
{
string ConnsecionString { get; set; }
string ContainerPath { get; set; }
void UploadFile(string filename, Stream s);
void DownloadFile(string filename, Stream s);
void DeleteFile(string filename);
bool ExistsFile(string filename);
IEnumerable<string> ListFiles(string model);
IEnumerable<ControlCommand> GetCommands();
IEnumerable<List<CameraInfo>> GetRequests();
void SendResponse(List<CameraInfo> resp);
}
- ConnectionString:带有配置参数的字符串。
- ContainerPath:标识文件夹,blob容器名称等。
- UploadFile:发送Stream对象中提供的文件。
- DownloadFile:在提供的Stream对象中获取文件。
- DeleteFile:删除文件。
- ExistsFile:测试文件是否存在。
- ListFiles:枚举文件夹中的文件,其名称的开头必须与模型参数匹配 。
- GetCommands:枚举客户端发送的命令。
- GetRequests:枚举客户端发送的摄像头请求。
- SendResponse:发送命令或摄像机请求的响应。
我已经实现了两个存储协议。该DropBoxProtocol项目实施与使用的协议的Dropbox。在服务器端,这只是读取和写入Dropbox文件夹的文件。不需要连接字符串,因为文件夹是单独配置的。
在客户端中,这是实现的协议。它略有不同,界面在TWClientApp项目中定义:
public interface IStorageManager
{
Task DownloadFile(string filename, Stream s);
Task DeleteFile(string filename);
Task<bool> ExistsFile(string filename);
Task<List<string>> ListFiles(string model);
Task SendCommand(ControlCommand cmd);
Task SendRequest(List<CameraInfo> req);
Task<List<CameraInfo>> GetResponse(string id);
}
它是一个异步接口,成员数少于服务器端。实现并不像服务器那么容易; 我们必须使用Dropbox API与之交互。实现在DropBoxStorage类中,并且在_accessKey常量中,您必须将安全密钥设置为成功建立连接(在第一次编译代码之前不要忘记这样做,因为没有默认值)。
private const string _accessKey = "";
客户端App的几乎所有代码都在TWClientApp项目中,在CameraPage类中。数据的交换协议是通过文件,每个文件都有一个特殊的名称来识别它。这些是不同的文件名模式:
- 摄像机只写一个帧文件,当客户端读取帧时,它删除文件,服务器可以写另一个。该文件是jpg图片,名称为<CAMERA ID> _FRAME_ <CLIENT ID> .jpg。
- 照片的名称相似,可能有多张照片。名称模式为:<CAMERA ID> _PHOTO_yyyyMMddHHmmss.jpg。
- 客户端可以以JSON文本格式和名称cmd_ <CLIENT ID> .json将命令一次发送到服务器。
- 当服务器获取命令文件时,它会删除该文件,因此客户端可以发送另一个命令,并执行该命令。然后,它编写一个名为resp_ <CLIENT ID> .json的响应文件。
- 最后,客户端可以发送相机请求,例如拍摄照片,或以JSON格式在名为req_ <CLIENT ID> .json的文件中启动或停止相机。服务器读取文件,删除它,并将请求传递给摄像机进行处理,然后,服务器写入响应文件,就像命令一样,具有摄像机状态。
该NetWave相机协议配置对话框非常简单,你可以阅读更多关于此协议中我的博客。
至于VAPIX协议,它更复杂,因为它是专业相机的协议。我没有使用包含大量控件的复杂对话框,而是实现了一个包含所有配置参数的树视图(它们是很多配置参数),您可以在其中选择每个参数并更改值。您也可以在我的博客中阅读更多相关信息。
这就是全部,享受解决方案,并感谢阅读!
项目源代码下载地址:http://www.codesocang.com/jiaocheng/news/_NETjishu/39173.html
C#实现完整的防盗自制监控系统的更多相关文章
- 开源视频监控系统:iSpy
iSpy是一个开源的视频监控软件,目前已经支持中文.自己用了一下,感觉还是很好用的.翻译了一下它的介绍. iSpy将PC变成一个完整的安全和监控系统 iSpy使用您的摄像头和麦克风来检测和记录声音或运 ...
- 优秀开源项目之一:视频监控系统iSpy
iSpy是一个开源的视频监控软件,目前已经支持中文.自己用了一下,感觉还是很好用的.翻译了一下它的介绍. iSpy将PC变成一个完整的安全和监控系统 iSpy使用您的摄像头和麦克风来检测和记录声音或运 ...
- Zabbix监控系统深度实践
Zabbix监控系统深度实践(企业级分布式系统自动化运维必选利器,大规模Zabbix集群实战经验技巧总结,由浅入深全面讲解配置.设计.案例和内部原理) 姚仁捷 著 ISBN 978-7-121-24 ...
- 基于 HTML5 WebGL 的低碳工业园区监控系统
前言 低碳工业园区的建设与推广是我国推进工业低碳转型的重要举措,低碳工业园区能源与碳排放管控平台是低碳工业园区建设的关键环节.如何对园区内的企业的能源量进行采集.计量.碳排放核算,如何对能源消耗和碳排 ...
- Zabbix监控系统
前言: 一个初略自动化运维平台,应该实现以下3个层面自动化: 1.操作系统层面自动化 如果想要万台服务器共舞,没有操作系统这个舞台还怎么舞? 1.1:物理环境: OS预备自动安装(Pxe/KickSt ...
- 基于 HTML5 WebGL 的计量站三维可视化监控系统 Web 组态工控应用
得益于 HTML5 WebGL 技术的成熟,从技术上对工控管理的可视化,数据可视化变得简单易行!完成对工控设备的管理效率,资源管理,风险管理等的大幅度提高,同时也对国家工业4.0计划作出有力响应! 如 ...
- VSAM:视频监控系统 A System for Video Surveillance and Monitoring
VSAM(VideoSurveillance and Monitoring)视频监控系统 Robotics Institute CMU 1:引言 2:试验床介绍 3:基本的视频分析算法:运动目标检测, ...
- 微信团队原创分享:iOS版微信的内存监控系统技术实践
本文来自微信开发团队yangyang的技术分享. 一.前言 FOOM(Foreground Out Of Memory),是指App在前台因消耗内存过多引起系统强杀.对用户而言,表现跟crash一样. ...
- 大众点评CAT开源监控系统剖析
参考文档: 大众点评的实时监控系统分析(一) CAT_source_analyze 透过CAT,来看分布式实时监控系统的设计与实现 深度剖析开源分布式监控CAT [分布式监控CAT] Client端源 ...
随机推荐
- 开源播放器 ijkplayer (六) :Android 下使用 ijkplayer 异常处理思路
一. java.lang.IllegalStateException: mpjni: setOptionLong: null mp 根据已查到的资料看,目前是ijk内部的问题,只能通过try& ...
- 你必须知道的10个Python第三库
1. BeautifulSoup Beautiful Soup是一个可以从HTML,XML进行提取文件的Python库,日常我们使用爬虫进行数据抓取回来之后,往往需要进行数据解析. 使用它能让你开心愉 ...
- [Swift]LeetCode213. 打家劫舍 II | House Robber II
You are a professional robber planning to rob houses along a street. Each house has a certain amount ...
- [Swift]LeetCode407. 接雨水 II | Trapping Rain Water II
Given an m x n matrix of positive integers representing the height of each unit cell in a 2D elevati ...
- [Swift]LeetCode623. 在二叉树中增加一行 | Add One Row to Tree
Given the root of a binary tree, then value v and depth d, you need to add a row of nodes with value ...
- winform文件筛选器
在.net 框架中,微软给我们封装了一个用于打开文件的对话框——OpenFileDialog.而该对话框包含一个可以筛选文件的属性——Filter,利用该属性,可选筛选出我们需要的文件. 因此,我 ...
- Hbase篇--Hbase和MapReduce结合Api
一.前述 Mapreduce可以自定义Inputforma对象和OutPutformat对象,所以原理上Mapreduce可以和任意输入源结合. 二.步骤 将结果写会到hbase中去. 2.1 Ma ...
- 【Maven】---坐标与依赖
Maven坐标与依赖 最近想深度学习下maven,找到一本书叫<Maven实战>,这本书讲的确实很好,唯一遗憾的是当时maven教学版本是3.0.0的,而目前已经到了3.5.4了,版本存在 ...
- Spring Security OAuth 2.0
续·前一篇<OAuth 2.0> OAuth 2.0 Provider 实现 在OAuth 2.0中,provider角色事实上是把授权服务和资源服务分开,有时候它们也可能在同一个应用中, ...
- C#版 - Leetcode 191. Number of 1 Bits-题解
版权声明: 本文为博主Bravo Yeung(知乎UserName同名)的原创文章,欲转载请先私信获博主允许,转载时请附上网址 http://blog.csdn.net/lzuacm. C#版 - L ...