1. 程式人生 > >C#實現完整的防盜自制監控系統

C#實現完整的防盜自制監控系統

因此 進制 oid 目錄 打電話 相關信息 reader 異步 了解

在您的手機中通知您家中的入侵者,並拍攝他們的照片

介紹

在本文中,我將展示一些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協議,它更復雜,因為它是專業相機的協議。我沒有使用包含大量控件的復雜對話框,而是實現了一個包含所有配置參數的樹視圖(它們是很多配置參數),您可以在其中選擇每個參數並更改值。您也可以在我的博客中閱讀更多相關信息。

這就是全部,享受解決方案,並感謝閱讀!

C#實現完整的防盜自制監控系統