using MQTTnet; using MQTTnet.Client; using MQTTnet.Client.Options; using MQTTnet.Formatter; using MQTTnet.Implementations; using MyCore.Models.Meross; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Net.Http.Headers; using System.Text; using System.Threading; using System.Threading.Tasks; namespace MyCore.Services { public class MerossService { // API HTTP private const string _merossUrl = "https://iot.meross.com"; private static string _secret = "23x17ahWarFH6w29"; private string _loginUrl = $"{_merossUrl}/v1/Auth/Login"; private string _logUrl = $"{_merossUrl}/v1/log/user"; private string _devList = $"{_merossUrl}/v1/Device/devList"; private static string username = "thomas.fransolet@hotmail.be"; private static string password = "Coconuts07"; private static ResultToken resultToken; // API MQTT private const int port = 2001; private const string domain = "iot.meross.com"; private IMqttClient _client; private IMqttClientOptions _options; private string _userMQTT; private string _passwordMQTT; public class Credential { public string email; public string password; } public class ResultToken { public string userid; public string email; public string token; public string key; } public enum RequestType { Login, Log, DeviceList } public MerossService() { try { var loginTask = Task.Run(() => PostURI(new Uri(_loginUrl), RequestType.Login)); loginTask.Wait(); if (loginTask.Result != "") { var data = ((JObject)JsonConvert.DeserializeObject(loginTask.Result))["data"]; resultToken = JsonConvert.DeserializeObject(data.ToString()); var deviceTask = Task.Run(() => PostURI(new Uri(_devList), RequestType.DeviceList)); deviceTask.Wait(); if (deviceTask.Result != "") { data = ((JObject)JsonConvert.DeserializeObject(deviceTask.Result))["data"]; var test = JsonConvert.DeserializeObject>(data.ToString()); } var logTask = Task.Run(() => PostURI(new Uri(_logUrl), RequestType.Log)); logTask.Wait(); if (logTask.Result != "") { data = ((JObject)JsonConvert.DeserializeObject(logTask.Result))["data"]; } //MQTT CONNEXION ConnexionToMqtt(); } } catch (Exception e) { resultToken = null; } } static async Task PostURI(Uri u, RequestType requestType) { var response = string.Empty; var requestParam = ""; string nonce = GenerateNonce(16).ToUpper(); var timeStamp = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds(); switch (requestType) { case RequestType.Login: requestParam = Base64Encode(JsonConvert.SerializeObject(new Credential { email = username, password = password }).ToString()); break; case RequestType.Log: requestParam = Base64Encode("{'extra': { }, 'model': 'Android,Android SDK built for x86_64', 'system': 'Android','uuid': '493dd9174941ed58waitForOpenWifi', 'vendor': 'Meross', 'version': '6.0'}"); break; case RequestType.DeviceList: requestParam = "e30="; break; } string stringForMD5 = stringForMD5 = _secret + timeStamp.ToString() + nonce + requestParam; string md5 = CreateMD5(stringForMD5); var payloadLogin = "{ \"params\":\"" + requestParam + "\",\"sign\":\"" + md5.ToLower() + "\",\"timestamp\":" + timeStamp + ",\"nonce\":\"" + nonce + "\"}"; using (var client = new HttpClient()) { HttpContent c = new StringContent(payloadLogin, Encoding.UTF8, "application/json"); if (resultToken != null) { client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", resultToken.token); } else { client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic"); } client.DefaultRequestHeaders.Add("vender", "Meross"); client.DefaultRequestHeaders.Add("AppVersion", "1.3.0"); client.DefaultRequestHeaders.Add("AppLanguage", "EN"); client.DefaultRequestHeaders.Add("User-Agent", "okhttp/3.6.0"); HttpResponseMessage result = await client.PostAsync(u, c); if (result.IsSuccessStatusCode) { response = await result.Content.ReadAsStringAsync(); } } return response; } public static string Base64Encode(string plainText) { var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText); return System.Convert.ToBase64String(plainTextBytes); } public static string CreateMD5(string input) { // Use input string to calculate MD5 hash using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create()) { byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input); byte[] hashBytes = md5.ComputeHash(inputBytes); // Convert the byte array to hexadecimal string StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append(hashBytes[i].ToString("X2")); } return sb.ToString(); } } private static string validChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; private static Random random = new Random(); private static string GenerateNonce(int length) { var nonceString = new StringBuilder(); for (int i = 0; i < length; i++) { nonceString.Append(validChars[random.Next(0, validChars.Length - 1)]); } return nonceString.ToString(); } private void ConnexionToMqtt() { try { // Create a new MQTT client. _client = new MqttFactory().CreateMqttClient(); string stringForMD5 = resultToken.userid + resultToken.key; string hashed_password = CreateMD5(stringForMD5); MqttClientOptionsBuilderTlsParameters tlsParameters = new MqttClientOptionsBuilderTlsParameters(); tlsParameters.UseTls = true; tlsParameters.SslProtocol = System.Security.Authentication.SslProtocols.Tls; _options = new MqttClientOptionsBuilder() .WithClientId("app: 08d4c9f99da40203ebc798a79512ec14") .WithTcpServer(domain, port) .WithCredentials(resultToken.userid, hashed_password) .WithTls(tlsParameters) .WithProtocolVersion(MqttProtocolVersion.V311) .Build(); _client.ConnectAsync(_options, CancellationToken.None).ContinueWith(res => { if (res.Status == TaskStatus.RanToCompletion) { Console.WriteLine("It's connected"); } else { Console.WriteLine($"Error connecting to {domain}"); } }); _client.UseDisconnectedHandler(async e => { Console.WriteLine("### DISCONNECTED FROM SERVER ###"); await Task.Delay(TimeSpan.FromSeconds(5)); try { await _client.ConnectAsync(_options, CancellationToken.None); // Since 3.0.5 with CancellationToken } catch { Console.WriteLine("### RECONNECTING FAILED ###"); } }); _client.UseConnectedHandler(async e => { Console.WriteLine("### CONNECTED WITH SERVER ###"); // Subscribe to a topic await _client.SubscribeAsync(new TopicFilterBuilder().WithTopic("#").Build()); Console.WriteLine("### SUBSCRIBED ###"); }); _client.UseApplicationMessageReceivedHandler(e => { Console.WriteLine("### RECEIVED APPLICATION MESSAGE ###"); Console.WriteLine($"+ Topic = {e.ApplicationMessage.Topic}"); Console.WriteLine($"+ Payload = {Encoding.UTF8.GetString(e.ApplicationMessage.Payload)}"); Console.WriteLine($"+ QoS = {e.ApplicationMessage.QualityOfServiceLevel}"); Console.WriteLine($"+ Retain = {e.ApplicationMessage.Retain}"); Console.WriteLine(); }); } catch (Exception e) { } } } }