當前位置: 妍妍網 > 碼農

Homekit.Net 1.0.0釋出:.NET原生SDK,助力打造私人智慧家居新體驗

2024-04-20碼農

前言

hi 大家好,我是三合,作為一個非著名懶人,每天上完班回到家,癱在沙發上一動都不想動,去開個燈我都嫌累,此時,智慧家居拯救了我,只需要在手機點點點,開關燈,空調,窗簾就都搞定了,一開始我用的是開源的home assistan,俗稱HA,搭配上hass-xiaomi-miot以及hap-python這幾個外掛程式,就可以將米家的智慧家居裝置接入蘋果的homekit生態,整體而言在蘋果手機上使用體驗非常好,但是有一個致命的問題,每隔一段時間,米家的裝置在homekit上就會失效,需要我重設,為此沒少被老婆埋怨這智慧家居怎麽這麽難用,然後ha又是python寫的,說句實話,我不太喜歡這種動態語言,各種奇怪用法,看得我雲裏霧裏,更談不上偵錯了,此時我就在想,如果我用c#寫homeKit和米家的sdk,自己搞一個智慧家居,豈不美哉,畢竟有了原生api,那就有了無限可能。

有了這個奇怪的想法後,我首先上github上搜尋了c#的智慧家居sdk,發現c#在智慧家居這個領域,幾乎一片空白,更談不上原生的sdk了,基本都是python的計畫,即使有一些c#的,也需要搭配ha或者HAP-NodeJS使用, 沒辦法,我只能參考hass-xiaomi-miot這個計畫移植了米家的sdk並命名為【MiHome.Net】,以及參考hap-python這個計畫移植了蘋果homekit的sdk並命名為【Homekit.Net】,MiHome.Net還在為開源前作最後的程式碼修改,正是蘋果homekit的sdk【Homekit.Net】,接下來,我將介紹他的用法。

HomeKit中的一些基本概念

HomeKit中每一個智慧家居稱為一個配件(Accessory),每個配件擁有多個服務(Services),每個服務又有多個特征(characteristics),所有配件都有配件資訊服務,這個服務裏包含了2個特性,1名字,2固件版本號,並且配件根據功能還有另外一些獨有的服務,我們以一個開關為例,開關本身就是一個配件,配件種類是switch,他就擁有一個服務叫Switch,這個服務下面,有一個特性叫on,也就是開關,我們給這個特性賦值true,就代表開,賦值false,就代表關。

Homekit.Net存在的意義

透過本依賴包,使用者可以透過程式碼模擬出各種各樣的智慧家居裝置,並添加到蘋果手機的家庭app中,這樣我們就能在手機上控制這些模擬的智慧家居裝置執行一些我們在程式碼裏配置好的操作,比如我們可以透過程式碼控制電腦開啟或者關閉某個套用,然後利用本庫封裝為一個開關,那麽我們就可以用家庭app中的這個模擬開關來控制套用了。有了原生api,大家就可以盡情的發揮想象力去搞事情了,比如DIY一個自動餵魚機?

Getting Started

Nuget

接下來我將演示如何使用【Homekit.Net】,你可以執行以下命令在你的計畫中安裝 Homekit.Net 。

PM> Install-Package Homekit.Net

支持框架

net 6,net 8

範例

透過繼承類Accessory,我們就可以自訂一個自己的配件,在下面的範例中,我們定義一個開關,在建構函式中,我們載入一個名為Switch的服務,並且定義配件型別為開關,從switch服務中獲取on這個特性,透過操作on這個特性,我們就可以透過程式碼模擬開關狀態變化了,並且可以在蘋果手機的家庭app上看到開關狀態的變化。

public classSwitch : Accessory
{
privatebool IsOn;
private Timer timer;
public Characteristics CurrentOnCharacteristics { getset; }
publicevent Action<object> OnChange; 
publicSwitch(AccessoryDriver accessoryDriver, string name, int? aid = null) : base(accessoryDriver, name, aid)
{
//載入switch開關服務
var service = AddPreloadService("Switch");
//定義配件種類為開關
Category = Category.CATEGORY_SWITCH;
//從switch服務中獲取on這個特性
CurrentOnCharacteristics = service.GetCharacteristics("On");
//添加開關狀態被家庭app改變後的回呼函式
CurrentOnCharacteristics.SetValueCallback = (o =>
{
OnChange(o);
this.IsOn = (bool)o ;
});
//定義一個定時器,定時改變開關狀態,用來模擬開關狀態變化
//timer = new Timer(Test, default, TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(30));
}
publicvoidTest(object? state)
{
var random = new Random();
var number = random.Next(150);
var isOn = number % 2 == 0;
CurrentOnCharacteristics.SetValue(isOn);
timer.Change(TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(30));
}
}

接下來,我們再來一個範例,定義一個溫度傳感器,在建構函式中,我們載入一個名為TemperatureSensor的服務,並且定義配件型別為傳感器,從TemperatureSensor服務中獲取CurrentTemperature(當前溫度)這個特性,透過程式碼操作CurrentTemperature這個特性,我們就可以模擬溫度變化,並且在蘋果手機的家庭app上看到溫度變化了。

public classTemperatureSensor : Accessory
{
public Characteristics CurrentTemperatureCharacteristics { getset; }
private Timer timer;
publicTemperatureSensor(AccessoryDriver accessoryDriver, string name, CancellationToken token = default) : base(accessoryDriver, name)
{
//載入TemperatureSensor溫度服務
var service = AddPreloadService("TemperatureSensor");
//定義配件種類為傳感器
Category = Category.CATEGORY_SENSOR;
//從TemperatureSensor服務中獲取CurrentTemperature(當前溫度)這個特性
CurrentTemperatureCharacteristics = service.GetCharacteristics("CurrentTemperature");
//設定溫度為1
CurrentTemperatureCharacteristics.SetValue(1);
//定義一個定時器,定時改變溫度,用來模擬溫度變化
timer = new Timer(Test, token, TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(30));
}
publicvoidTest(object? state)
{
if (state is CancellationToken token && token.IsCancellationRequested)
{
return;
}
// Console.WriteLine(DateTime.Now+"觸發了定時任務");
var random = new Random();
var wd = random.Next(150);
// Console.WriteLine($"設定溫度為{wd}度");
CurrentTemperatureCharacteristics.SetValue(wd);
timer.Change(TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(30));
}
}



更多的配件型別,歡迎大家自行解鎖,配件的所有服務和特征匯總,可以在程式執行起來後,檢視Resources資料夾下的json檔

配件定義結束以後,我們就要讓這個配件跑起來了,新建一個控制台程式,程式碼如下:

internal classProgram
 {
privateasyncstatic Task SingleAccessory()
{
var cts = new CancellationTokenSource();
//先定義驅動
var driver = new AccessoryDriver(port: 6555);
//定義配件
var switchAccessory1 = new Switch(driver, "switch開關");
//添加開關狀態被蘋果手機的家庭app改變後的回呼
switchAccessory1.OnChange += async (o) =>
{
Console.WriteLine("The switch state has changed.開關狀態變化了");
};
driver.AddAccessory(switchAccessory1);
await driver.StartAsync(cts.Token);
}
privateasyncstatic Task MultipleAccessories()
{
var cts = new CancellationTokenSource();
//先定義驅動
var driver = new AccessoryDriver(port: 6554);
//定義閘道器
var bridge = new Bridge(driver, "閘道器");
//定義配件1開關
var switchAccessory1 = new Switch(driver, "開關switch");
bridge.AddAccessory(switchAccessory1);
//添加開關狀態被蘋果手機的家庭app改變後的回呼
switchAccessory1.OnChange += async (o) =>
{
Console.WriteLine("The switch state has changed.開關狀態變化了");
};
//定義配件2傳感器
var temperatureSensor= new TemperatureSensor(driver, "傳感器TemperatureSensor");
bridge.AddAccessory(temperatureSensor);
driver.AddAccessory(bridge);
await driver.StartAsync(cts.Token);
}
asyncstatic Task Main(string[] args)
{
//Test Multiple Accessories 測試單配件
await SingleAccessory();
//Test Multiple Accessories 測試多配件
//await MultipleAccessories();
}
 }





以上這段代分碼為2個部份,SingleAccessory單配件範例,和MultipleAccessories多配件範例,大體流程就是首先定義一個驅動,接著例項化之前定義的配件,並且把配件加入到驅動中,最後啟動驅動即可。啟動後效果如下圖,他會在控制台上打印出一個二維碼,

接著我們使用蘋果手機的家庭app掃描這個二維碼(添加配件需要在同一個區域網路中),即可添加我們程式碼中自訂的配件。

如果我們想在程式中定義多個配件,那麽參考MultipleAccessories方法,首先得定義一個閘道器,接著把我們定義的多個配件添加到閘道器裏,最後再啟動驅動。

開源地址

本計畫基於MIT協定開源,地址為 https://github.com/TripleView/HomeKit.Net

同時感謝以下計畫

1、HAP-Python:https://github.com/ikalchev/HAP-python

2、ZeroConfig:https://github.com/cosinekitty/zeroconfig

轉自:三合視角

連結:cnblogs.com/hezp/p/18142099

- EOF -

推薦閱讀 點選標題可跳轉

看完本文有收獲?請轉發分享給更多人

推薦關註「DotNet」,提升.Net技能

點贊和在看就是最大的支持❤️