Skip to content

Instantly share code, notes, and snippets.

@mikaeldui
Last active December 22, 2021 18:10
Show Gist options
  • Save mikaeldui/7b02b784695ef968859afafbf541d581 to your computer and use it in GitHub Desktop.
Save mikaeldui/7b02b784695ef968859afafbf541d581 to your computer and use it in GitHub Desktop.
Small Xiaomi MiWiFi .NET Client with some endpoints. Can get devices connected to Wi-Fi.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Windows.Security.Cryptography;
using Windows.Security.Cryptography.Core;
using Windows.Storage.Streams;
using System.Text.Json;
using System.Net.Http.Json;
using System.Dynamic;
using System.Net.NetworkInformation;
namespace Xiaomi.WiFi
{
// Ported from https://github.com/scientifichackers/pymiwifi/blob/master/pymiwifi/api.py
public class MiWiFiClient : IDisposable
{
public const string PUBLIC_KEY = "a2ffa5c9be07488bbb04a3a47d3c5f6a";
private string _address;
private string _token;
private int _miWiFiType;
private HttpClient _httpClient = new HttpClient();
public MiWiFiClient(string address = "http://miwifi.com/", int miWiFiType = 0)
{
if (address.EndsWith('/'))
address = address.Substring(0, address.Length - 1);
_address = address;
_token = null;
_miWiFiType = miWiFiType;
}
public async Task<HttpResponseMessage> LoginAsync(string password)
{
var response = await _httpClient.GetAsync($"{_address}/cgi-bin/luci/api/xqsystem/login?username=admin&password={password}");
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
dynamic json = await response.Content.ReadFromJsonAsync<ExpandoObject>();
_token = json.token.GetString();
}
return response;
}
public async Task<HttpResponseMessage> LogoutAsync() =>
await _httpClient.GetAsync($"{_address}/cgi-bin/luci/;stok={_token}/web/logout");
public async Task<dynamic> GetApiEndpointAsync(string apiEndpoint)
{
HttpResponseMessage httpResponseMessage = await _httpClient.GetAsync($"{_address}/cgi-bin/luci/;stok={_token}/api/{apiEndpoint}");
dynamic response = await httpResponseMessage.Content.ReadFromJsonAsync<ExpandoObject>();
return response;
}
public Task<dynamic> GetStatusAsync() => GetApiEndpointAsync("misystem/status");
public Task<dynamic> GetDeviceListAsync() => GetApiEndpointAsync("misystem/devicelist");
public Task<dynamic> GetBandwidthTestAsync() => GetApiEndpointAsync("misystem/bandwidth_test");
public Task<dynamic> GetPppoeStatusAsync() => GetApiEndpointAsync("xqnetwork/pppoe_status");
public Task<dynamic> GetWiFiDetailAllAsync() => GetApiEndpointAsync("xqnetwork/wifi_detail_all");
public Task<dynamic> GetWifiConnectDevicesAsync() => GetApiEndpointAsync("xqnetwork/wifi_connect_devices");
public Task<dynamic> GetCountryCodeAsync() => GetApiEndpointAsync("xqsystem/country_code");
public Task<dynamic> GetInitInfoAsync() => GetApiEndpointAsync("xqsystem/init_info");
public Task<dynamic> GetWanInfo() => GetApiEndpointAsync("xqsystem/wan_info");
public Task<dynamic> CheckWanType() => GetApiEndpointAsync("xqsystem/check_wan_type");
private static string _sha1(string data)
{
IBuffer buffer = CryptographicBuffer.ConvertStringToBinary(data, BinaryStringEncoding.Utf8);
HashAlgorithmProvider hashAlgorithm = HashAlgorithmProvider.OpenAlgorithm(HashAlgorithmNames.Sha1);
IBuffer sha1 = hashAlgorithm.HashData(buffer);
byte[] newByteArray;
CryptographicBuffer.CopyToByteArray(sha1, out newByteArray);
var sb = new StringBuilder(newByteArray.Length * 2);
foreach (byte b in newByteArray)
{
sb.Append(b.ToString("x2"));
}
return sb.ToString();
}
private string _getMacAddress()
{
string macAddresses = "";
foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
{
// Only consider Ethernet network interfaces, thereby ignoring any
// loopback devices etc.
if (nic.NetworkInterfaceType != NetworkInterfaceType.Ethernet && nic.NetworkInterfaceType != NetworkInterfaceType.Wireless80211) continue;
if (nic.OperationalStatus == OperationalStatus.Up)
{
return string.Join(":", nic.GetPhysicalAddress().GetAddressBytes().Select(b => b.ToString("X2")));
break;
}
}
return macAddresses;
}
private string _generateNonce(int miwifiType = 0)
{
string mac = _getMacAddress();
return $"{miwifiType}_{mac}_{((DateTimeOffset)DateTime.UtcNow).ToUnixTimeSeconds()}_{new Random().Next() * 1000}";
}
private static string _generatePasswordHash(string nonce, string password) => _sha1(nonce + _sha1(password + PUBLIC_KEY));
public void Dispose()
{
((IDisposable)_httpClient).Dispose();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment