Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Global upgrade #63

Draft
wants to merge 14 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion YeelightAPI.Console/YeelightAPI.Console.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net6.0</TargetFramework>

<IsPackable>false</IsPackable>

Expand Down
2 changes: 1 addition & 1 deletion YeelightAPI.Console/packages.config
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="12.0.3" targetFramework="net46" />
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net46" />
</packages>
14 changes: 7 additions & 7 deletions YeelightAPI.UnitTests/YeelightAPI.UnitTests.csproj
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net6.0</TargetFramework>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.5" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="3.1.5" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.2">
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
<PackageReference Include="xunit" Version="2.4.2-pre.12" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="1.3.0">
<PackageReference Include="coverlet.collector" Version="3.1.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
5 changes: 5 additions & 0 deletions YeelightAPI/Core/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ internal static class Constants
/// </summary>
public const int DefaultTimeout = 5000;

/// <summary>
/// Default starting port when searching available ports for music mode
/// </summary>
public const int DefaultMusicModeStartingPort = 5000;

/// <summary>
/// Line separator
/// </summary>
Expand Down
32 changes: 32 additions & 0 deletions YeelightAPI/Core/MusicModeInformations.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace YeelightAPI.Core
{
/// <summary>
/// Informations about device music mode
/// </summary>
public class MusicModeInformations
{
/// <summary>
/// The host name
/// </summary>
public string HostName { get; internal set; }

/// <summary>
/// The used port
/// </summary>
public int Port { get; internal set; }

/// <summary>
/// Music mode enabled or not ?
/// </summary>
public bool Enabled { get; internal set; }

/// <summary>
/// High rate enabled or not ?
/// </summary>
public bool HighRateEnabled { get; set; }
}
}
73 changes: 73 additions & 0 deletions YeelightAPI/Core/NetworkHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;

namespace YeelightAPI.Core
{
/// <summary>
/// Helper for networking operations
/// </summary>
public static class NetworkHelper
{
/// <summary>
/// Get the current IP adress
/// </summary>
/// <returns></returns>
public static string GetLocalIpAddress()
{
using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, 0))
{
socket.Connect("8.8.8.8", 65530);
IPEndPoint endPoint = socket.LocalEndPoint as IPEndPoint;
return endPoint.Address.ToString();
}
}

/// <summary>
/// Get the next available port
/// </summary>
/// <param name="startingPort">the port number to start searching from</param>
/// <returns></returns>
public static int GetNextAvailablePort(int startingPort = 0)
{
IPEndPoint[] endPoints;
List<int> portArray = new List<int>();

IPGlobalProperties properties = IPGlobalProperties.GetIPGlobalProperties();

//getting active connections
TcpConnectionInformation[] connections = properties.GetActiveTcpConnections();
if (connections.Any(c => c.LocalEndPoint.Port >= startingPort))
{
portArray.Add(connections.First(c => c.LocalEndPoint.Port >= startingPort).LocalEndPoint.Port);
}

//getting active tcp listners
endPoints = properties.GetActiveTcpListeners();
if (endPoints.Any(c => c.Port >= startingPort))
{
portArray.Add(endPoints.First(c => c.Port >= startingPort).Port);
}

//getting active udp listeners
endPoints = properties.GetActiveUdpListeners();
if (endPoints.Any(c => c.Port >= startingPort))
{
portArray.Add(endPoints.First(c => c.Port >= startingPort).Port);
}

if (portArray.Count != 0)
{
portArray.Sort();
return portArray.First();
}

throw new Exception("No Available Port");

}
}
}
56 changes: 47 additions & 9 deletions YeelightAPI/Device.IDeviceController.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Threading.Tasks;
using YeelightAPI.Core;
Expand Down Expand Up @@ -335,31 +337,38 @@ public async Task<bool> StartColorFlow(ColorFlow flow)
}

/// <summary>
/// Starts the music mode
/// starts the music mode for all devices, with specified port (or automatic port chosing if <paramref name="startingPort"/> is null)
/// </summary>
/// <param name="hostname"></param>
/// <param name="port"></param>
/// <param name="startingPort"></param>
/// <returns></returns>
public async Task<bool> StartMusicMode(string hostname = null, int port = 12345)
public async Task<bool> StartMusicMode(string hostname, int? startingPort)
{
//init new TCP socket
if (string.IsNullOrWhiteSpace(hostname))
{
hostname = GetLocalIpAddress();
hostname = NetworkHelper.GetLocalIpAddress();
}

var listener = new TcpListener(System.Net.IPAddress.Parse(hostname), port);
if (!startingPort.HasValue)
{
startingPort = NetworkHelper.GetNextAvailablePort(Constants.DefaultMusicModeStartingPort);
}

var listener = new TcpListener(System.Net.IPAddress.Parse(hostname), startingPort.Value);
listener.Start();

List<object> parameters = new List<object>() { (int)MusicAction.On, hostname, port };
List<object> parameters = new List<object>() { (int)MusicAction.On, hostname, startingPort.Value };

CommandResult<List<string>> result = await ExecuteCommandWithResponse<List<string>>(
method: METHODS.SetMusicMode,
parameters: parameters);

if (result.IsOk())
{
this.IsMusicModeEnabled = true;
this.MusicMode.Enabled = true;
this.MusicMode.HostName = hostname;
this.MusicMode.Port = startingPort.Value;
this.Disconnect();
var musicTcpClient = await listener.AcceptTcpClientAsync();
_tcpClient = musicTcpClient;
Expand All @@ -368,6 +377,36 @@ public async Task<bool> StartMusicMode(string hostname = null, int port = 12345)
return result.IsOk();
}

/// <summary>
/// starts the music mode for all device, with specified ports
/// </summary>
/// <param name="hostName"></param>
/// <param name="ports"></param>
/// <returns></returns>
/// <exception cref="InvalidDataException"></exception>
public Task<bool> StartMusicMode(string hostName, IEnumerable<int> ports)
{
if (ports == null || ports.Count() != 1)
throw new InvalidDataException("ports collection must have exactly one element");

return StartMusicMode(hostName, ports.First());
}

/// <summary>
/// starts the music mode for all device, with possibility to specify a Func that will be called for reach device to determine its port
/// </summary>
/// <param name="hostName"></param>
/// <param name="portChooser"></param>
/// <returns></returns>
/// <exception cref="InvalidDataException"></exception>
public Task<bool> StartMusicMode(string hostName, Func<Device, int> portChooser)
{
if (portChooser == null)
throw new InvalidDataException("portChooser parameter cannot be null");

return StartMusicMode(hostName, portChooser.Invoke(this));
}

/// <summary>
/// Stops the color flow
/// </summary>
Expand Down Expand Up @@ -395,8 +434,7 @@ public async Task<bool> StopMusicMode()
if (result.IsOk())
{
//disables the music mode
this.IsMusicModeEnabled = false;
await DisableMusicModeAsync();
this.MusicMode.Enabled = false;
return true;
}

Expand Down
26 changes: 13 additions & 13 deletions YeelightAPI/Device.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,16 @@ public bool IsConnected
/// <summary>
/// Indicate wether the music mode is enabled
/// </summary>
public bool IsMusicModeEnabled { get; private set; }
[Obsolete("IsMusicModeEnabled will be removed in the next version, please use MusicMode property instead")]
public bool IsMusicModeEnabled
{
get => this.MusicMode.Enabled;
}

/// <summary>
/// Give informations about the music mode
/// </summary>
public MusicModeInformations MusicMode { get; private set; } = new MusicModeInformations();

/// <summary>
/// The model.
Expand Down Expand Up @@ -247,9 +256,10 @@ public void ExecuteCommand(METHODS method, List<object> parameters = null)
/// <returns></returns>
public async Task<CommandResult<T>> ExecuteCommandWithResponse<T>(METHODS method, List<object> parameters = null)
{
if (IsMusicModeEnabled)
if (this.MusicMode.Enabled)
{
//music mode enabled, there will be no response, we should assume everything works
_tcpClient.Client.NoDelay = this.MusicMode.HighRateEnabled; //update here instead of "SetMusicMode" so it can be changed dynamically
int uniqueId = GetUniqueIdForCommand();
ExecuteCommand(method, uniqueId, parameters);
return new CommandResult<T>() { Id = uniqueId, Error = null, IsMusicResponse = true };
Expand Down Expand Up @@ -324,24 +334,14 @@ internal async Task<CommandResult<T>> ExecuteCommandWithResponse<T>(METHODS meth
internal async Task DisableMusicModeAsync()
{
_ = await Connect();
IsMusicModeEnabled = false;
MusicMode.Enabled = false;

}

#endregion INTERNAL METHODS

#region PRIVATE METHODS

private static string GetLocalIpAddress()
{
using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, 0))
{
socket.Connect("8.8.8.8", 65530);
IPEndPoint endPoint = socket.LocalEndPoint as IPEndPoint;
return endPoint.Address.ToString();
}
}

/// <summary>
/// Generate valid parameters for percent values
/// </summary>
Expand Down
Loading