当前位置: 移动技术网 > IT编程>开发语言>.net > C#实现完整的防盗自制监控系统

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

2018年12月21日  | 移动技术网IT编程  | 我要评论

与鸦熊共舞,陈迪生,酒国豪放女

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

介绍

在本文中,我将展示一些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作为将照片上传到云端的最简单,最便宜的方式,我还使用此媒体将移动客户端与控制中心进行通信,使用带有的文本文件。

控制中心

在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协议,它更复杂,因为它是专业相机的协议。我没有使用包含大量控件的复杂对话框,而是实现了一个包含所有配置参数的树视图(它们是很多配置参数),您可以在其中选择每个参数并更改值。您也可以在我的博客中阅读更多相关信息。

这就是全部,享受解决方案,并感谢阅读!

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网