From 98041c07a322e50b01eef1a7c6822edb27f1785d Mon Sep 17 00:00:00 2001 From: Thomas Fransolet Date: Fri, 7 Feb 2020 22:24:16 +0100 Subject: [PATCH] ArloService - Login, Get Devices, Get Library + SSE WIP (Connection working but no event recorded) --- MyCore/Models/Arlo/ArloDevice.cs | 65 ++++++++++ MyCore/Models/Arlo/UserLocation.cs | 12 ++ MyCore/Models/Arlo/UserMedia.cs | 38 ++++++ MyCore/MyCore.csproj | 2 + MyCore/Services/ArloService.cs | 201 ++++++++++++++++++++++++++++- MyCore/Services/MerossService.cs | 4 + MyCore/Startup.cs | 4 +- 7 files changed, 323 insertions(+), 3 deletions(-) create mode 100644 MyCore/Models/Arlo/ArloDevice.cs create mode 100644 MyCore/Models/Arlo/UserLocation.cs create mode 100644 MyCore/Models/Arlo/UserMedia.cs diff --git a/MyCore/Models/Arlo/ArloDevice.cs b/MyCore/Models/Arlo/ArloDevice.cs new file mode 100644 index 0000000..52d8dde --- /dev/null +++ b/MyCore/Models/Arlo/ArloDevice.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace MyCore.Models.Arlo +{ + public class ArloDevice + { + public string userId { get; set; } + public string deviceId { get; set; } + public string parentId { get; set; } + public string uniqueId { get; set; } + public string deviceType { get; set; } + public string deviceName { get; set; } + public string xCloudId { get; set; } + public string userRole { get; set; } + public int displayOrder { get; set; } + public string state { get; set; } + public string modelId { get; set; } + public bool cvrEnabled { get; set; } + public long dateCreated { get; set; } + public string skillNumber { get; set; } + public Owner owner { get; set; } + + //Camera Specific + public string lastImageUploaded { get; set; } + public string presignedLastImageUrl { get; set; } + public string presignedSnapshotUrl { get; set; } + public string presignedFullFrameSnapshotUrl { get; set; } + public int mediaObjectCount { get; set; } + public bool arloMobilePlan { get; set; } + public string interfaceVersion { get; set; } + public string interfaceSchemaVer { get; set; } + public Properties properties { get; set; } + + //Base Station Specific + public Connectivity connectivity { get; set; } + public string certAvailable { get; set; } + public int automationRevision { get; set; } + public bool migrateActivityZone { get; set; } + + } + + public class Owner + { + public string firstName { get; set; } + public string lastName { get; set; } + public string ownerId { get; set; } + } + + public class Properties + { + public string modelId { get; set; } + public string olsonTimeZone { get; set; } + public string hwVersion { get; set; } + } + + public class Connectivity + { + public string type { get; set; } + public bool connected { get; set; } + public string mepStatus { get; set; } + } +} diff --git a/MyCore/Models/Arlo/UserLocation.cs b/MyCore/Models/Arlo/UserLocation.cs new file mode 100644 index 0000000..3d2f084 --- /dev/null +++ b/MyCore/Models/Arlo/UserLocation.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace MyCore.Models.Arlo +{ + public class UserLocation + { + // TODO + } +} diff --git a/MyCore/Models/Arlo/UserMedia.cs b/MyCore/Models/Arlo/UserMedia.cs new file mode 100644 index 0000000..8a01a64 --- /dev/null +++ b/MyCore/Models/Arlo/UserMedia.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace MyCore.Models.Arlo +{ + public class UserMedia + { + public string ownerId { get; set; } + public string uniqueId { get; set; } + public string deviceId { get; set; } + public string createdDate { get; set; } + public string currentState { get; set; } + public string name { get; set; } + public string contentType { get; set; } + public string reason { get; set; } + public string createdBy { get; set; } + public long lastModified { get; set; } + public long localCreatedDate { get; set; } + public string presignedContentUrl { get; set; } + public string presignedThumbnailUrl { get; set; } + public long utcCreatedDate { get; set; } + public string timeZone { get; set; } + public string mediaDuration { get; set; } + public Meta meta { get; set; } + public int mediaDurationSecond { get; set; } + public bool donated { get; set; } + } + + public class Meta + { + public string bit_rate { get; set; } + public string width { get; set; } + public string codec_tag_string { get; set; } + public string height { get; set; } + } +} diff --git a/MyCore/MyCore.csproj b/MyCore/MyCore.csproj index 59f9c9b..ecb61a8 100644 --- a/MyCore/MyCore.csproj +++ b/MyCore/MyCore.csproj @@ -16,6 +16,7 @@ + @@ -24,6 +25,7 @@ + diff --git a/MyCore/Services/ArloService.cs b/MyCore/Services/ArloService.cs index a188b0e..887edf6 100644 --- a/MyCore/Services/ArloService.cs +++ b/MyCore/Services/ArloService.cs @@ -1,11 +1,208 @@ -using System; +using EvtSource; +using MyCore.Models.Arlo; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using ServiceStack; +using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text; using System.Threading.Tasks; namespace MyCore.Services { public class ArloService { + // API HTTP + private const string _arloUrl = "https://arlo.netgear.com/hmsweb"; + + private string _loginUrl = $"{_arloUrl}/login/v2"; + private string _userProfileUrl = $"{_arloUrl}/users/profile"; + private string _userSessionUrl = $"{_arloUrl}/users/session"; + private string _userFriendsUrl = $"{_arloUrl}/users/friends"; + private string _userLocationUrl = $"{_arloUrl}/users/locations"; + private string _userServiceLevelUrl = $"{_arloUrl}/users/serviceLevel/v2"; + private string _userDevicesUrl = $"{_arloUrl}/users/devices"; + private string _userLibraryUrl = $"{_arloUrl}/users/library"; + private string _userLibraryMetadataUrl = $"{_arloUrl}/users/library/metadata/v2"; + private string _userPaymentOffersUrl = $"{_arloUrl}/users/payment/offers"; + + private string _userDevicesNotifyUrl = $"{_arloUrl}/users/devices/notify"; + private string _clientSubscribeUrl = $"{_arloUrl}/client/subscribe"; + + + private static string _email = "fransolet.thomas@gmail.com"; + private static string _password = "Coconuts09"; + + private static LoginResult resultToken; + + private List allArloDevices; + private List allUserMedias; + + public class Credential + { + public string email; + public string password; + } + + public class DateInterval + { + public string dateFrom; + public string dateTo; + } + + public class LoginResult + { + public string userId; + public string email; + public string token; + public string paymentId; + public int authenticated; + public string accountStatus; + public string serialNumber; + public string countryCode; + public bool tocUpdate; + public bool policyUpdate; + public bool validEmail; + public bool arlo; + public long dateCreated; + } + + public enum RequestType + { + Get, + Post + } + + public enum Request + { + LOGIN, + DEVICES, + LIBRARY + } + + public ArloService() + { + + try + { + // LOGIN + var loginTask = Task.Run(() => RequestURI(new Uri(_loginUrl), RequestType.Post, Request.LOGIN)); + loginTask.Wait(); + + if (loginTask.Result != "") + { + //RESULT TOKEN + var data = ((JObject)JsonConvert.DeserializeObject(loginTask.Result))["data"]; + resultToken = JsonConvert.DeserializeObject(data.ToString()); + + // GET DEVICE LIST + var deviceTask = Task.Run(() => RequestURI(new Uri(_userDevicesUrl), RequestType.Get, Request.DEVICES)); + deviceTask.Wait(); + + if (deviceTask.Result != "") + { + data = ((JObject)JsonConvert.DeserializeObject(deviceTask.Result))["data"]; + // RETRIEVE ALL ARLO DEVICES + allArloDevices = JsonConvert.DeserializeObject>(data.ToString()); + } + + // GET USER LIBRARY + var libraryTask = Task.Run(() => RequestURI(new Uri(_userLibraryUrl), RequestType.Post, Request.LIBRARY)); + libraryTask.Wait(); + + if (libraryTask.Result != "") + { + data = ((JObject)JsonConvert.DeserializeObject(libraryTask.Result))["data"]; + // RETRIEVE ALL DATA IN USER LIBRARY + allUserMedias = JsonConvert.DeserializeObject>(data.ToString()); + } + + //SSE CONNEXION + ConnexionToSSE(); + } + } + catch (Exception e) + { + resultToken = null; + } + } + + static async Task RequestURI(Uri u, RequestType requesType, Request request) + { + try + { + var response = string.Empty; + var body = ""; + HttpContent c = null; + using (var client = new HttpClient()) + { + switch (request) + { + case Request.LOGIN: + body = JsonConvert.SerializeObject(new Credential { email = _email, password = _password }).ToString(); + c = new StringContent(body, Encoding.UTF8, "application/json"); + break; + case Request.LIBRARY: + DateTime last7Days = new DateTime(DateTime.Now.Year, 1, 1).AddDays(DateTime.Now.DayOfYear - 7 - 1); + body = JsonConvert.SerializeObject(new DateInterval { dateFrom = last7Days.ToString("yyyyMMdd"), dateTo = DateTime.Now.ToString("yyyyMMdd")}).ToString(); + c = new StringContent(body, Encoding.UTF8, "application/json"); + break; + case Request.DEVICES: + default: + break; + } + + client.DefaultRequestHeaders.Add("User-Agent", "okhttp/3.6.0"); + + if (resultToken != null) + client.DefaultRequestHeaders.Add("Authorization", resultToken.token); + + if (requesType == RequestType.Get) + { + HttpResponseMessage result = await client.GetAsync(u); + response = await result.Content.ReadAsStringAsync(); + } + + if (requesType == RequestType.Post) + { + + HttpResponseMessage result = await client.PostAsync(u, c); + if (result.IsSuccessStatusCode) + response = await result.Content.ReadAsStringAsync(); + } + } + return response; + } + catch (Exception e) + { + Console.WriteLine("ArloService - An error occured in RequestURI"); + return null; + } + } + + public void ConnexionToSSE() + { + /*var sseClient = new ServerEventsClient($"{_clientSubscribeUrl}?token={resultToken.token}", new string[] { "EventStream" }) + { + OnConnect = e => { + Console.WriteLine($"{e.IsAuthenticated}, {e.UserId}, {e.DisplayName}"); + } + }.Start();*/ + + var evt = new EventSourceReader(new Uri($"{_clientSubscribeUrl}?token={resultToken.token}")).Start(); + evt.MessageReceived += + (object sender, EventSourceMessageEventArgs e) + => + Console.WriteLine($"{e.Event} : {e.Message}"); + evt.Disconnected += async (object sender, DisconnectEventArgs e) => { + Console.WriteLine($"Retry: {e.ReconnectDelay} - Error: {e.Exception}"); + await Task.Delay(e.ReconnectDelay); + evt.Start(); // Reconnect to the same URL + }; + } + } -} +} \ No newline at end of file diff --git a/MyCore/Services/MerossService.cs b/MyCore/Services/MerossService.cs index 1f39de6..da1e331 100644 --- a/MyCore/Services/MerossService.cs +++ b/MyCore/Services/MerossService.cs @@ -197,6 +197,9 @@ namespace MyCore.Services return nonceString.ToString(); } + + #region MQTT + public class RequestMQTT { public HeaderMqtt header; @@ -500,5 +503,6 @@ namespace MyCore.Services if (_client.IsConnected) _client.PublishAsync(mqttMessage); } + #endregion } } diff --git a/MyCore/Startup.cs b/MyCore/Startup.cs index 733ec87..79d79b9 100644 --- a/MyCore/Startup.cs +++ b/MyCore/Startup.cs @@ -28,7 +28,9 @@ namespace MyCore //MQTTService mQTTService = new MQTTService(); - MerossService merossService = new MerossService(); + //MerossService merossService = new MerossService(); + + ArloService arloService = new ArloService(); } public IConfiguration Configuration { get; }