C#实现完整的防盗自制监控系统

在您的手机中通知您家中的入侵者,并拍摄他们的照片php

介绍

在本文中,我将展现一些DIY东西​​,用于安装监控系统,检测家中的入侵者,拍摄照片并经过手机通知您,必要时能够打电话给警察并提供照片以便快速识别劫匪,并提升你恢复全部被盗事物的机会。html

固然,除了这个软件,你必须提供一些硬件,但我已经在我家使用相对便宜的材料建造了这个系统,若是咱们除了相机,这是安装中最昂贵的部分。但你能够用相机作不少事情,因此它能够是一个好的和有趣的投资。git

基本上,这是系统架构,包含全部参与元素:json

虽然在模式中我已经表明了一些具体的子系统,但实际上我已经设计了解决方案,以便经过实现公共接口并使用依赖注入将它们与应用程序连接,能够独立开发全部这些元素。不一样的子系统或协议以下:安全

  • 摄像机协议:定义与摄像机的通讯。
  • 存储协议:定义文件传输,图像和控制命令/响应。
  • 触发协议:启动监控系统。
  • 警报协议:将事件远程传达给用户。

该解决方案使用Visual Studio 2015和4.5版的.Net Framework实现。服务器

你能够在个人博客中找到这篇文章的更长版本网站源码,这里有西班牙文版本。因为此站点的文件大小限制为10MB,我不得不删除源代码中的大量文件,全部NuGet包,obj目录和全部二进制文件。虽然您能够从Visual Studio还原包,但您可能没法从新编译代码。在这种状况下,您能够从个人网站,在上一个连接中下载项目的完整文件集。架构

硬件

让咱们回顾一下我用来构建系统的硬件。因为应用程序能够经过多种方式进行扩展,所以您可使用本身的不一样硬件选择来安装它。app

首先是相机。我有两个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

相关文章
相关标签/搜索