279 lines
12 KiB
C#

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<ArloDevice> allArloDevices;
private List<UserMedia> 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;
}
// Motion Detection Test - {"from":"XXX-XXXXXXX_web","to":"XXXXXXXXXXXXX","action":"set","resource":"cameras/XXXXXXXXXXXXX","transId":"web!XXXXXXXX.XXXXXXXXXXXXXXXXXXXX","publishResponse":true,"properties":{"motionSetupModeEnabled":true,"motionSetupModeSensitivity":80}}
public class MotionDetection
{
public string from;
public string to;
public string action;
public string resource;
public string transId;
public bool publishResponse = true;
public PropertiesRequestMotionSubscription properties;
}
public class PropertiesRequest
{
public bool motionSetupModeEnabled;
public int motionSetupModeSensitivity;
}
public class PropertiesRequestMotionSubscription
{
public string[] devices;
}
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<LoginResult>(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<List<ArloDevice>>(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<List<UserMedia>>(data.ToString());
}
//SSE CONNEXION
ConnexionToSSE();
}
}
catch (Exception e)
{
resultToken = null;
}
}
static async Task<string> 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 +=
async (object sender, EventSourceMessageEventArgs e)
=>
{
using (var client = new HttpClient())
{
ArloDevice baseStation = allArloDevices.Where(d => d.deviceType == "basestation").FirstOrDefault();
ArloDevice camera = allArloDevices.Where(d => d.deviceType == "camera").FirstOrDefault();
Console.WriteLine($"{e.Event} : {e.Message}");
// ask for motion event test
//Motion Detection Test - { "from":"XXX-XXXXXXX_web","to":"XXXXXXXXXXXXX","action":"set","resource":"cameras/XXXXXXXXXXXXX","transId":"web!XXXXXXXX.XXXXXXXXXXXXXXXXXXXX","publishResponse":true,"properties":{ "motionSetupModeEnabled":true,"motionSetupModeSensitivity":80} }
/*MotionDetection motionDetection = new MotionDetection();
motionDetection.from = $"{baseStation.userId}_web";
motionDetection.to = $"{baseStation.deviceId}";
motionDetection.action = "set";
motionDetection.resource = $"cameras/{camera.deviceId}";
motionDetection.transId = $"web!XXXXXXXX.XXXXXXXXXXXXXXXXXXXX";
motionDetection.publishResponse = true;
PropertiesRequest propertiesRequest = new PropertiesRequest();
propertiesRequest.motionSetupModeEnabled = true;
propertiesRequest.motionSetupModeSensitivity = 80;
motionDetection.properties = propertiesRequest;
var body = JsonConvert.SerializeObject(motionDetection).ToString();*/
// Try to subscribe to motion for camera
/*MotionDetection motionDetection = new MotionDetection();
motionDetection.from = $"{baseStation.userId}_web";
motionDetection.to = $"{baseStation.deviceId}";
motionDetection.action = "set";
motionDetection.resource = $"subscriptions/{baseStation.userId}_web";
motionDetection.transId = $"web!XXXXXXXX.XXXXXXXXXXXXXXXXXXXX";
motionDetection.publishResponse = false;
PropertiesRequestMotionSubscription propertiesRequestMotionSubscription = new PropertiesRequestMotionSubscription();
propertiesRequestMotionSubscription.devices = new string[] { camera.deviceId };
motionDetection.properties = propertiesRequestMotionSubscription;
var body = JsonConvert.SerializeObject(motionDetection).ToString();
HttpContent c = new StringContent(body, Encoding.UTF8, "application/json");
client.DefaultRequestHeaders.Add("xcloudId", baseStation.xCloudId);
client.DefaultRequestHeaders.Add("Authorization", resultToken.token);
HttpResponseMessage result = await client.PostAsync($"{ _userDevicesNotifyUrl}/{baseStation.deviceId}", c);
if (result.IsSuccessStatusCode)
{
var response = await result.Content.ReadAsStringAsync();
}*/
}
};
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
};
}
}
}