C# Library for using xiaomi smart gateway in your automation scenarious
This library provides simple and flexible C# API for Xiaomi Mi Home devices.
Currently supports only Gateway version 2 (DGNWG02LM), Air Humidifier (zhimi.humidifier.v1), Mi Robot vacuum (rockrobo.vacuum.v1) and several sensors. See the pictures below.
Table of Contents
- Installation
- Setup Gateway
- Basic scenario
- Supported devices
- 4.1 Gateway
- 4.1.1 Gateway radio
- 4.2 Temparature & humidity sensor
- 4.3 Socket plug
- 4.4 Motion sensor
- 4.5 Door/Window sensor
- 4.6 Water leak sensor
- 4.7 Smoke sensor
- 4.8 Wireless dual wall switch
- 4.9 Aqara cube
- 4.10 Air humidifier
- 4.11 Mi Robot Vacuum
- 4.1 Gateway
Installation
via nuget package manager
Install-Package MiHomeLib
or
dotnet add package MiHomeLib
or install via GitHub packages
Setup Gateway
Before using this library you should setup development mode on your gateway, instructions how to do this.
This mode allows to work with the gateway via UDP multicast protocol.
Warning 1: If you bought a newer revision of Mi Home Gateway (labels in a circle)
It could be possible that ports on your gateway required for UDP multicast traffic are closed.
Before using this library ports must be opened. Check this instruction.
Warning 2: Mi Home Gateway uses udp multicast for messages handling, so your app must be hosted in the same LAN as your gateway. If it is not you have to use multicast routers like udproxy or igmpproxy or vpn bridging.
Warning 3: If your app is running on windows machine, make sure that you disabled virtual network adapters like VirtualBox, Hyper-V, Npcap, pcap etc. Because these adapters may prevent proper work of multicast traffic between your machine and gateway
Basic scenario
Get all devices in the network
public static void Main(string[] args)
{
// gateway password is optional, needed only to send commands to your devices
// gateway sid is optional, use only when you have 2 gateways in your LAN
// using var miHome = new MiHome("gateway password", "gateway sid");
using var miHome = new MiHome();
miHome.OnAnyDevice += (_, device) =>
{
Console.WriteLine($"{device.Sid}, {device.GetType()}, {device}"); // all discovered devices
};
Console.ReadLine();
}
Supported devices
Gateway
1.using var miHome = new MiHome("gateway password here"); // here we using developers api
miHome.OnGateway += (_, gateway) =>
{
gateway.EnableLight(); // by default this is "white" light
Task.Delay(3000).Wait();
gateway.DisableLight(); // light off
Task.Delay(3000).Wait();
gateway.EnableLight(255, 0, 0, 100); // turn on "red" light with full brightness
Task.Delay(3000).Wait();
gateway.DisableLight(); // light off
Task.Delay(3000).Wait();
gateway.PlaySound(Gateway.Sound.IceWorldPiano, 50); // play ice world piano sound on gateway with volume 50%
Task.Delay(3000).Wait();
gateway.SoundsOff();
gateway.PlayCustomSound(10_002, 50); // play custom sound with volume 50%
Task.Delay(3000).Wait();
gateway.SoundsOff();
};
Yes, it is possible to upload custom sounds to your gateway and use them in various scenarios. Check this instruction.
Gateway Radio
1.1It is possible to add/remove/play custom radio channels in this version of gateway.
Bellow is a simple code snippet explaining how to use this feature.
var gw = new MiioGateway("192.168.1.12", "<your gateway token here>");
var radioChannels = gw.GetRadioChannels(); // get list of available custom radio channels
foreach (var channel in radioChannels)
{
Console.WriteLine(channel);
}
gw.AddRadioChannel(1025, "http://192.168.1.1/my-playlist.m3u8"); // add custom radio channel
Task.Delay(1000).Wait();
gw.PlayRadio(1024, 50); // play newly-added channel with volume 50%
Task.Delay(1000).Wait();
gw.StopRadio(); // stop playing radio
Task.Delay(1000).Wait();
gw.RemoveRadioChannel(1024); // remove newly-added channel
Task.Delay(1000).Wait();
gw.RemoveAllRadioChannels(); // remove all custom radio channels
Async methods also supported.
Warning 1: Added radio channels are not persistant. Gateway may remove them from time to time. Warning 2: My gateway recognizes only songs in aac format (mp3 is not supported).
Here is minimal working sample of m3u8 file that gateway recognizes and respects.
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:1
#EXTINF:240,
http://192.168.1.2/test.aac
EXT-X-MEDIA-SEQUENCE - number of songs in your playlist.
EXTINF - track length in seconds.
http://192.168.1.2/test.aac - url to your song
Temperature and humidity sensor
2.using var miHome = new MiHome();
miHome.OnThSensor += (_, thSensor) =>
{
if (thSensor.Sid == "158d000182dfbc") // sid of specific device
{
Console.WriteLine(thSensor); // Sample output --> Temperature: 22,19°C, Humidity: 74,66%, Voltage: 3,035V
thSensor.OnTemperatureChange += (_, e) =>
{
Console.WriteLine($"New temperature: {e.Temperature}");
};
thSensor.OnHumidityChange += (_, e) =>
{
Console.WriteLine($"New humidity: {e.Humidity}");
};
}
};
Socket Plug (zigbee version)
3.using var miHome = new MiHome();
miHome.OnSocketPlug += (_, socketPlug) =>
{
if (socketPlug.Sid == "158d00015dc6cc") // sid of specific device
{
Console.WriteLine(socketPlug); // sample output Status: on, Inuse: 1, Load Power: 2.91V, Power Consumed: 37049W, Voltage: 3.6V
socketPlug.TurnOff();
Task.Delay(5000).Wait();
socketPlug.TurnOn();
}
};
Motion sensor or Aqara motion sensor
4.using var miHome = new MiHome();
//miHome.OnAqaraMotionSensor += (_, motionSensor) =>
miHome.OnMotionSensor += (_, motionSensor) =>
{
if (motionSensor.Sid == "158d00015dc6cc") // sid of specific device
{
Console.WriteLine(motionSensor); // sample output Status: motion, Voltage: 3.035V, NoMotion: 0s
motionSensor.OnMotion += (_, __) =>
{
Console.WriteLine($"{DateTime.Now}: Motion detected !");
};
motionSensor.OnNoMotion += (_, e) =>
{
Console.WriteLine($"{DateTime.Now}: No motion for {e.Seconds}s !");
};
}
};
Door/Window sensor or Aqara open/close sensor
5.using var miHome = new MiHome();
//miHome.OnAqaraOpenCloseSensor += (_, windowSensor) =>
miHome.OnDoorWindowSensor += (_, windowSensor) =>
{
if (windowSensor.Sid == "158d00015dc6cc") // sid of specific device
{
Console.WriteLine(windowSensor); // sample output Status: close, Voltage: 3.025V
windowSensor.OnOpen += (_, __) =>
{
Console.WriteLine($"{DateTime.Now}: Window opened !");
};
windowSensor.OnClose += (_, __) =>
{
Console.WriteLine($"{DateTime.Now}: Window closed !");
};
}
};
Water leak sensor
6.using var miHome = new MiHome();
miHome.OnWaterLeakSensor += (_, waterLeakSensor) =>
{
if (waterLeakSensor.Sid == "158d00015dc6cc") // sid of specific device
{
Console.WriteLine(waterLeakSensor); // Status: no_leak, Voltage: 3.015V
waterLeakSensor.OnLeak += (_, __) =>
{
Console.WriteLine("Water leak detected !");
};
waterLeakSensor.OnNoLeak += (_, __) =>
{
Console.WriteLine("NO leak detected !");
};
}
};
Smoke sensor
7.using var miHome = new MiHome();
miHome.OnSmokeSensor += (_, smokeSensor) =>
{
if (smokeSensor.Sid == "158d00015dc6cc") // sid of specific device
{
Console.WriteLine(smokeSensor); // sample output Alarm: off, Density: 0, Voltage: 3.075V
smokeSensor.OnAlarm += (_, __) =>
{
Console.WriteLine("Smoke detected !");
};
smokeSensor.OnAlarmStopped += (_, __) =>
{
Console.WriteLine("Smoke alarm stopped");
};
smokeSensor.OnDensityChange += (_, e) =>
{
Console.WriteLine($"Density changed {e.Density}");
};
}
};
Wireless dual wall switch
8.using var miHome = new MiHome();
miHome.OnWirelessDualWallSwitch += (_, wirelessDualSwitch) =>
{
if (wirelessDualSwitch.Sid == "158d00015dc6cc") // sid of specific device
{
Console.WriteLine(wirelessDualSwitch);
wirelessDualSwitch.OnLeftClick += (_) =>
{
Console.WriteLine("Left button clicked !");
};
wirelessDualSwitch.OnRightDoubleClick += (_) =>
{
Console.WriteLine("Right button double clicked !");
};
wirelessDualSwitch.OnLeftLongClick += (_) =>
{
Console.WriteLine("Left button long clicked !");
};
}
};
Aqara cube
9.using var miHome = new MiHome();
miHome.OnAqaraCubeSensor += (_, aqaraQube) =>
{
if (aqaraQube.Sid == "158d00015dc6cc") // sid of specific device
{
Console.WriteLine(aqaraQube);
aqaraQube.OnStatusChanged += (sender, eventArgs) =>
{
Console.WriteLine($"{sender} | {eventArgs.Status}");
};
}
};
Air Humidifier
10.Before using the library you need to know IP and TOKEN of your air humidifier. If you don't know these parameters try to use the following code in order to discover air humidifiers in your LAN
AirHumidifier.OnDiscovered += (_, humidifier) =>
{
Console.WriteLine($"ip: {humidifier.Ip}, token: {humidifier.Token}");
// sample output ip: 192.168.1.5, token: 4a3a2f017b70097a850558c35c953b55
};
AirHumidifier.DiscoverDevices();
If your device hides his token follow these instructions in order to extract it.
Basic scenario
var airHumidifier = new AirHumidifier("<ip here>", "<token here>");
Console.WriteLine(airHumidifier);
/* sample output
Power: on
Mode: high
Temperature: 32.6 °C
Humidity: 34%
LED brightness: bright
Buzzer: on
Child lock: off
Target humidity: 50%
Model: zhimi.humidifier.v1
IP Address:192.168.1.5
Token: 4a3a2f017b70097a850558c35c953b55
*/
Functions
var airHumidifier = new AirHumidifier("<ip here>", "<token here>");
airHumidifier.PowerOn(); // power on
airHumidifier.PowerOff(); // power off
airHumidifier.SetMode(AirHumidifier.Mode.High); // set fan mode high/medium/low
airHumidifier.GetTemperature(); // get temperature
airHumidifier.GetHumidity(); // get humidity
airHumidifier.SetBrightness(AirHumidifier.Brightness.Bright); // set brighness bright/dim/off
airHumidifier.BuzzerOn(); // set buzzer sound on
airHumidifier.BuzzerOff(); // set buzzer sound off
airHumidifier.ChildLockOn(); // set child lock on
airHumidifier.ChildLockOff(); // set child lock oаа
airHumidifier.GetTargetHumidity(); // get humidity limit 20/30/40/50/60/70/80 %
Async versions of the operations above also supported.
Mi Robot Vacuum
11.Before using the library you need to know IP and TOKEN of your Mi Robot.
If you don't know these parameters try to use the following code in order to discover mi robots in your LAN
MiRobotV1.OnDiscovered += (_, e) =>
{
Console.WriteLine($"{e.Ip}, {e.Serial}, {e.Type}, {e.Token}");
};
MiRobotV1.DiscoverDevices()
If your device hides his token (you get 'ffffffffffffffffffffffffffffffff' instead of token) follow these instructions in order to extract it.
Supported methods
var miRobot = new MiRobotV1("<ip here>", "<token here>");
miRobot.Start(); // start the clean up
miRobot.Stop(); // stop the clean up
miRobot.Pause(); // pause the clean up
miRobot.Spot(); // start spot clean up
miRobot.Home(); // go back to the base station
miRobot.FindMe(); // tell the robot to give a voice
Async versions of the operations above also supported.
Warning: Mi Robot stores client requests in memory and doesn't allow to send request with the same client id twice.
It means that if you run the code snippet bellow twice.
var miRobot = new MiRobotV1("<ip here>", "<token here>");
miRobot.Start(); // start the clean up
The second attempt will fail. Work around is to set client id manually (usually increasing to 1 works)
var miRobot = new MiRobotV1("<ip here>", "<token here>", 2); // client request id is set to 2
miRobot.Start(); // start the clean up