Last active
December 22, 2021 18:10
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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