MerossService Api Http ok, MQTT WIP

This commit is contained in:
Thomas Fransolet 2020-01-19 02:34:19 +01:00
parent 0139257a28
commit 1cd7a56d1b
8 changed files with 310 additions and 4 deletions

Binary file not shown.

View File

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace MyCore.Models.Meross
{
public class MerossDevice
{
public string uuid { get; set; }
public int onlineStatus { get; set; }
public string devName { get; set; }
public string devIconId { get; set; }
public long bindTime { get; set; }
public string deviceType { get; set; }
public string subType { get; set; }
public List<Channel> channels { get; set; }
public string region { get; set; }
public string firmwareVersion { get; set; }
public string hdwareVersion { get; set; }
public string userDevIcon { get; set; }
public int iconType { get; set; }
public string skillNumber { get; set; }
public string domain { get; set; }
public string reservedDomain { get; set; }
}
public class Channel
{
public string type { get; set; }
public string devName { get; set; }
public string devIconId { get; set; }
}
}

View File

@ -17,7 +17,6 @@ namespace MyCore.Services
{ {
public class MQTTService public class MQTTService
{ {
private IMqttClient _client; private IMqttClient _client;
private IMqttClientOptions _options; private IMqttClientOptions _options;
private string _mqttServer = "192.168.31.140"; private string _mqttServer = "192.168.31.140";
@ -112,9 +111,11 @@ namespace MyCore.Services
// If so retrieve the device in database and his Type // If so retrieve the device in database and his Type
// Retrieve the object // Retrieve the device as an object (We have a defined list of devices. That's not a problem, it's a choice as we want reliability)
// Check in the list of automations if we have something to do with the message // Check in the list of automations if we have something to do with the message (Check in mqtt input section)
// Automation = id, name,
// Load everydevice in cache.. ? Performance ? // Load everydevice in cache.. ? Performance ?

View File

@ -0,0 +1,269 @@
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<ResultToken>(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<List<MerossDevice>>(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<string> 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)
{
}
}
}
}

View File

@ -26,7 +26,9 @@ namespace MyCore
{ {
Configuration = configuration; Configuration = configuration;
MQTTService mQTTService = new MQTTService(); //MQTTService mQTTService = new MQTTService();
MerossService merossService = new MerossService();
} }
public IConfiguration Configuration { get; } public IConfiguration Configuration { get; }