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

相關文章
相關標籤/搜索