C#で書いたECHONET Lite の簡単なコントールサンプル

　ECHONET Liteのコントローラの制御関連のプログラムをC#で書きたかったのですが、ネット検索してもあまりヒットしなかったので自作しました。
　サンプルコードはGithubの[echonetlitecsリポジトリ](https://github.com/tarosay/echonetlitecs)に置いています。
## サンプルの説明
![pic1.png](https://qiita-image-store.s3.amazonaws.com/0/32065/251e4f1a-c703-8fcd-58c3-717ccf424e70.png)
　「一覧の取得」ボタンを押すとLAN内のECHONET Liteノード一覧を取得します。ノードが取得できると、下のノード欄に1つ目に取得したノードコードがセットされます。次の欄にインスタンス番号がセットされます。
　「オン」「オフ」ボタンは、スイッチのオンオフを行うボタンです。図の一覧に表示されている0290は一般照明のノードコードですので「オン」「オフ」ボタンを押すと、照明を点けたり消したりできます。

## ノード一覧の取得
一覧の取得はUDPマルチキャストすることによって、ノードからの返信を取得します。
ポートは3610、アドレスは224.0.23.0 です。とりあえず、PortとMulticastAddressを設定しています。

```cs:ECHONET_Lite.cs
 private static readonly int Port = 3610;
 private static readonly string MulticastAddress = "224.0.23.0";
 private static readonly UInt16 Header = 0x1081;
 private static readonly UInt16 TransactionID = 0x0000;
 private static readonly byte ControllerGrpCd = 0x05;
 private static readonly byte ControllerClsCd = 0xFF;
 private static readonly byte ControllerInsCd = 0x01;
```

　UDPマルチキャストするとノードの返信はUDPユニキャストで返ってきます。なので、UDPマルチキャストを送信した後にUDPユニキャストで受信します。プログラムは以下です(エラー処理は省いています)。

```cs:ECHONET_Lite.cs
//ノード一覧を取得するためにマルチキャストします
using (UdpClient udpClient = new UdpClient(AddressFamily.InterNetwork))
{
  IPAddress address = IPAddress.Parse(MulticastAddress);
  IPEndPoint ipEndPoint = new IPEndPoint(address, Port);
  udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, Port));
  udpClient.JoinMulticastGroup(address, IPAddress.Parse(LocalAddress));
  udpClient.MulticastLoopback = true;
  byte[] frame = CreateSearchFrame();
  udpClient.Send(frame, frame.Length, ipEndPoint);
}
//マルチキャストの返信がユニキャストで来るので取得します
byte[] recvBytes = null;
IPEndPoint remoteEP = null;
using (UdpClient udp = new UdpClient(Port))
{
  udp.Client.ReceiveTimeout = 5000;   //5secでタイムアウト
  recvBytes = udp.Receive(ref remoteEP);
}
```
　これで、recvBytes[]にノード一覧のフレームデータが入っています。ノードのIPアドレスは remoteEP.Address に入っています。
　listにノードデータを追加しています。

```cs:ECHONET_Lite.cs
List<EObject> list = new List<EObject>();
string ipaddress = remoteEP.Address.ToString();
//取得したノードをlistに入れます
for (int i = 0; i < nodeCnt; i++)
{
  EObject eo = new EObject();
  eo.Number = i + 1;
  eo.IPAddress = ipaddress;
  eo.GroupCd = recvBytes[15 + i * 3];
  eo.ClassCd = recvBytes[15 + i * 3 + 1];
  eo.InstanceCd = recvBytes[15 + i * 3 + 2];
  list.Add(eo);
}
 ```
ECHONET Liteとは直接関係ないですが、マルチキャストの際に自身のローカルIPアドレスを付加しておかないとUDPユニキャストが返って来ないようです。ローカルIPアドレスのプロパティを追加しました。フォームのソースコードの方に自身のローカルIPアドレスを取得するメソッドも入れています。
## スイッチのオンオフ
ECHONET Liteのコントロールサンプルとして、スイッチのオンオフサンプルコードを付けています。スイッチのオンオフ用フレームをUDPユニキャストで送信するだけです。

```cs:ECHONET_Lite.cs
public byte[] SwitchSet(EObject eo, bool sw)
{
  byte[] sendFrame = CreateSwitchFrame(eo, sw);   //スイッチ用のフレームを取得します
  byte[] recvBytes = null;

  IPEndPoint remoteEP = null;
  using (UdpClient udp = new UdpClient(Port))
  {
    udp.Client.ReceiveTimeout = 5000;   //5secでタイムアウト
    udp.Send(sendFrame, sendFrame.Length, eo.IPAddress, Port);
    recvBytes = udp.Receive(ref remoteEP);
  }
  return recvBytes;
}
 ```
　 SwitchSet()は、スイッチ用のフレーム生成するメソッドです。プロパティ番号0x80がスイッチのオンオフプロパティです。

```cs:ECHONET_Lite.cs
private byte[] CreateSwitchFrame(EObject eo, bool sw)
{
  byte[] frame = new byte[15];
  frame[0] = (byte)(Header >> 8);         //EHD1 ECHONETLiteヘッダ  1Byte   0x10固定
  frame[1] = (byte)(Header & 0xFF);       //EHD2 ECHONETLiteヘッダ  1Byte   0x81固定
  frame[2] = (byte)(TransactionID >> 8);  //TID  トランザクションID 2Byte   0～65535
  frame[3] = (byte)(TransactionID & 0xFF);//TID  トランザクションID 2Byte   0～65535
  frame[4] = ControllerGrpCd;             //SEOJ 送信元オブジェクト コントローラークラスグループコード
  frame[5] = ControllerClsCd;             //SEOJ 送信元オブジェクト コントローラークラスコード
  frame[6] = ControllerInsCd;             //SEOJ 送信元オブジェクト インスタンスコード
  frame[7] = eo.GroupCd;                  //DEOJ 送信先オブジェクト グループコード
  frame[8] = eo.ClassCd;                  //DEOJ 送信先オブジェクト クラスコード
  frame[9] = eo.InstanceCd;               //DEOJ 送信先オブジェクト インスタンスコード
  frame[10] = (byte)enmESV.SETC;           //ESV  サービスコード     SETC
  frame[11] = (byte)0x01;                 //OPC  プロパティ数
  frame[12] = (byte)0x80;                 //EPC  プロパティ番号     スイッチのオンオフ
  frame[13] = (byte)0x01;                 //PDC  EDTのバイト数
  frame[14] = sw ? (byte)0x30 : (byte)0x31;   //0x30がスイッチオン 0x31がスイッチオフ
  return frame;
}
 ```

　簡単ですが、こんな感じでC#から制御できるようになりました。