TP-linkスマートプラグを.net 5.0から制御する。

#TP-linkスマートプラグについて
スマートプラグは、検索するといろいろなメーカーからでていますが、安心して使えそうなメーカーは、SwitchBotかTP-link社のスマートプラグと思います。SwitchBot社はスマホから簡単に制御でき、Amazonアレクサにも簡単に連携できる優れものです。また、同社は赤外線ハブで、おおよその家電も制御できます。プログラムを書けない人が使うスマート機器としては優秀ですが、プログラマーとしては、やはり自分のコードで、しかもローカルなネットワーク環境で使いたくなります。TP-link社のHS105は、ローカルなネットワーク環境でプログラマーが自分のコード実行することができます。今回は、このスマートプラグをC#で、しかも、発表されたばかりの.net5で動作検証をしたと思います。



#TP-link HS105の概要
購入先：Amazonから容易に購入できます。

注意事項：コンセントのプラグ幅が左右で大きさが異なります。中国製で騙されたと思いましたが、よくよく調べると日本工業規格 JIS C 8303で規定されているまっとうなコンセント形状ということが分かりました。日本の電気の仕様的にはコンセントに差し込む向きを気にしない無極性プラグが普通だと思っていたので、この事実を知ると、世の中に出回っているコンセントのプラグ幅が同じであるほうがよくない気がしてきました。
海外では、3プラグ方式で、向きとアースが規定されているので、そのような環境でモノづくりしているメーカーは、日本市場用でも正しくプラグに極があるようにしているのかなと想像しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54916/58531a26-1a83-4879-68d8-09874d600a68.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54916/0c764ff6-f9fe-c1fb-af20-f3f3f15ce1ed.png)
自宅の備え付けコンセントをみると確かに左右でプラグ幅が異なります。



#通信方法
HS105は、Wifi経由で制御でき、通信仕様は非公開。ただGoogle先生で、「TP-link HS105 python」等の検索キーワードで調べると多数の文献がでてきます。
.net関連でもいくつかのライブラリが公開されていますが、いずれも.net frameworkを対象としたものです。
今回はGithubに公開されている「TPLinkSmartDevices」を使ってみたいと思います。


#試用環境
OS:Windows10 Pro 20H2
開発:Visual studio2019
言語１：C# .net Framework 4.5
言語２：C# .net 5.0
試用コード：TPLinkSmartDevices
https://github.com/anthturner/TPLinkSmartDevices

#ダウンロード＆ビルド

まずは、ダウンロードし、そのままビルドしたいと思います。
このプログラムは、Newtonsoft.Jsonを使っているので、まずはNugetを使ってインストールする必要があります。
Visual Studio2019であれば、画面下に復元ボタンが表示されますので、このボタンでインストールします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54916/8c2e3be3-2fa9-741e-c954-01491b549a2a.png)
プロジェクトのプロパティをみると、.net Framework 4.5で構成されていることがわかります。これは、今回そのままにしておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54916/4298eada-cb94-cce3-849d-cf322f0bd932.png)

実際にビルドしてみます。正常終了しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54916/0c105cca-4d92-9f2e-8349-3a6cc0d05180.png)

正常にDLLが出力されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54916/45efe1e9-d0d9-c540-71e5-6c2633fa56ea.png)

#.net Framework環境でテスト
では、このプログラムを使ってテストプログラムを作成してみたいと思います。
まずは新規プロジェクトで、.net Frameworkのコンソールアプリを作ります。
次に参照の追加で、先程作成したDLLを登録します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54916/733733ce-3800-c71a-95a3-456bda827c8e.png)

次に下記コードを記載し実行すると、ネットワークに接続されているTP-linkスマートプラグ関連を調べて、Hostname（IPアドレス）がコンソールに書き込まれます。

```csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            var discoveredDevices = new TPLinkSmartDevices.TPLinkDiscovery().Discover().Result;
            foreach (var item in discoveredDevices)
            {
                Console.WriteLine(item.Hostname);
            }
        }
    }
}

```
次に、入手した、Hostname（IPアドレス）を使ってスマートプラグのスイッチをON/OFFします。
補足
下記コードの"XXX.XXX.XXX.XXX"をご自分の環境に合わせて修正してください。

```csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            var smartPlug = new TPLinkSmartDevices.Devices.TPLinkSmartPlug("XXX.XXX.XXX.XXX");
            smartPlug.OutletPowered = true; // Turn on relay
            //smartPlug.OutletPowered = false; // Turn off relay
        }
    }
}

```
スマートプラグがリレースイッチがカチカチと音がすれば通信成功です。

#.net 5環境でテスト
ではこの調子で.net5のコンソールアプリのテストをしてみたいと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54916/381598a1-36d3-131c-6c2e-a8a1863563f4.png)

.net Coreのコンソールアプリの初期画面です。右側のソリューションエクスプローラの様子が、いままでと異なります。参照ではなく依存関係となっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54916/da044231-c178-9454-cdc4-0b3d16b5950a.png)

あと、このままでは、表題の.net5で試すことにはなりません。それはデフォルトでは.net Core3.1だからです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54916/f3068eeb-c8f9-3d95-bdfa-fa96131ce7f2.png)

ここを、.net5に変更します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54916/d8ac88b8-1c24-35ef-5833-d3ce693f407e.png)

次に依存関係を右クリックしてDLLを追加したいと思います。ただ、参照マネージャーを立ち上げたいだけなので、とりあえず、プロジェクト参照の追加を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54916/fe62b456-bd67-b18a-7b7d-fd0903c52f3d.png)

参照ボタンを選択し、前項で作成したTPLinkSmartDevices.dllを読み込みます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54916/7b355153-235a-1904-a471-cf52be13dad2.png)

無事登録されていることを確認。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54916/b9411f10-3ed4-bf5f-fb1d-ecb74802bbe3.png)

では、前項同様、まずはスマートプラグを探し出すコードを実行してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54916/7839e883-04ad-9da6-cd9d-977391307fa8.png)

```
System.AggregateException
  HResult=0x80131500
  Message=One or more errors occurred. (Could not load file or assembly 'System.Security.Permissions, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. 指定されたファイルが見つかりません。)
  Source=System.Private.CoreLib
  スタック トレース:
   at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
   at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
   at System.Threading.Tasks.Task`1.get_Result()
   at ConsoleAppNet5Test.Program.Main(String[] args) in C:\Users\XXXX\source\repos\ConsoleAppNet5Test\ConsoleAppNet5Test\Program.cs:line 9

内部例外 1:
FileNotFoundException: Could not load file or assembly 'System.Security.Permissions, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. 指定されたファイルが見つかりません。
```
ここで、.net5と.net Frameworkの間に壁が存在することがわかりましたが、正直このエラーを解決する手段がgoogle先生からは容易に見つかりません。.net Framework4からの.net Framework2 or .net Framework3-DLL参照とはわけが違います。
これの解決には、もう少し調べていく必要があるので、今回はTPLinkSmartDevices.dllの内容も含めて.net Coreでビルドする作戦に切り替えます。
先程参照設定したTPLinkSmartDevices.dllを削除します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54916/58d72c17-86d1-4492-560f-08b394a9c71e.png)

次にTPLinkSmartDevices.dllのソースコードをフォルダごと.net5のプロジェクトにコピーします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54916/66464704-21d9-4ae5-d9ed-546a3bc02ed9.png)

ここからがびっくりしたのですが、Visual Studio2019の.net Coreアプリプロジェクトでは、上記のコピーをしただけで、プロジェクトのコンパイル対象に登録されています。便利なのですが、意図しない取り込みもされそうで・・・今後注意すべき仕様ですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54916/1240d811-5ad2-2b7a-4fc1-a4a41e827fd2.png)

次に下記エラーをつぶしていく必要があります。Newtonsoft.Jsonがないためのエラーと思われるので、これをインストールします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54916/9100e3e3-adb0-4706-6c91-488c668770ea.png)

Newtonsoft.JsonのインストールにはNugetを使います。
```
Install-Package Newtonsoft.Json
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54916/fd19e3b3-3d7f-aba0-94c8-b8df6d59ec88.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54916/86bda752-7e19-99b4-e9e4-8319ca4d309c.png)

無事インストールが完了しましたら、エラーが消えたことを確認し、下記コードを実行します。
using TPLinkSmartDevices;を追加することがポイントです。


```csharp
using System;
using TPLinkSmartDevices;

namespace ConsoleAppNet5Test
{
    class Program
    {
        static void Main(string[] args)
        {
            var discoveredDevices = new TPLinkSmartDevices.TPLinkDiscovery().Discover().Result;
            foreach (var item in discoveredDevices)
            {
                Console.WriteLine(item.Hostname);
            }
        }
    
    }
```
最後に実行してみると、私の環境では無事実行できました。

#まとめ
.net Frameworkと.net5は、ソースコードレベルでは互換性があるようで、どららのフレームワークにもあるライブラリを呼び出したものであれば、.net Frameworkのコードを.net5でビルドし直すだけで問題は解決することがわかりました。前回の[Windows10 .net Core時代のGPIB制御　初級編](https://qiita.com/kokimu/items/9c77091cf39739c2dda2)でCOM参照、今回のビルドするフレームワークの変更で.net5がハードウェア制御にも使えることがわかりました。