From bb01b3342dd34a2dec9bbaf1e2c883f7b28ee589 Mon Sep 17 00:00:00 2001 From: Markus Bender Date: Sat, 3 Feb 2024 00:57:33 +0100 Subject: [PATCH] Version 1.1.0 (#3) * Delete .gitignore * Added Readme, Added Nuget Infos in Project * Added GoveeService that unites Api and Udp Service Added ColorTemp Method to Udp Service * Added UdpListener check * Added ApiKey check * Moved Class and changed Namespace * Update GoveeCSharpConnector.csproj --- .../GoveeCSharpConnector.csproj | 4 +- .../Interfaces/IGoveeApiService.cs | 19 ++-- .../Interfaces/IGoveeService.cs | 62 +++++++++++ .../Interfaces/IGoveeUdpService.cs | 9 ++ GoveeCSharpConnector/Objects/GoveeDevice.cs | 9 ++ GoveeCSharpConnector/Objects/GoveeState.cs | 11 ++ GoveeCSharpConnector/Objects/Properties.cs | 2 +- GoveeCSharpConnector/Services/GoveeService.cs | 100 ++++++++++++++++++ .../Services/GoveeUdpService.cs | 54 ++++++++-- README.md | 1 + 10 files changed, 250 insertions(+), 21 deletions(-) create mode 100644 GoveeCSharpConnector/Interfaces/IGoveeService.cs create mode 100644 GoveeCSharpConnector/Objects/GoveeDevice.cs create mode 100644 GoveeCSharpConnector/Objects/GoveeState.cs create mode 100644 GoveeCSharpConnector/Services/GoveeService.cs diff --git a/GoveeCSharpConnector/GoveeCSharpConnector.csproj b/GoveeCSharpConnector/GoveeCSharpConnector.csproj index 1027ab2..132f430 100644 --- a/GoveeCSharpConnector/GoveeCSharpConnector.csproj +++ b/GoveeCSharpConnector/GoveeCSharpConnector.csproj @@ -12,16 +12,14 @@ https://github.com/Locxion/GoveeCSharpConnector https://github.com/Locxion/GoveeCSharpConnector https://github.com/Locxion/GoveeCSharpConnector/blob/main/LICENSE + 1.1.0 - - - \ No newline at end of file diff --git a/GoveeCSharpConnector/Interfaces/IGoveeApiService.cs b/GoveeCSharpConnector/Interfaces/IGoveeApiService.cs index 5d4611e..70ef2c8 100644 --- a/GoveeCSharpConnector/Interfaces/IGoveeApiService.cs +++ b/GoveeCSharpConnector/Interfaces/IGoveeApiService.cs @@ -10,27 +10,32 @@ public interface IGoveeApiService /// /// Api Key as String void SetApiKey(string apiKey); + /// /// Returns current set Govee Api Key /// /// Govee Api Key as String string GetApiKey(); + /// /// Removes the Set Api Key and resets the HTTP Header /// void RemoveApiKey(); + /// /// Requests all Devices registered to Api Key Govee Account /// /// List of GoveeApiDevices Task> GetDevices(); + /// /// Requests the State of a single Govee Device /// /// Device Id Guid as string /// Device Model Number as string /// GoveeApiStat Object - public Task GetDeviceState(string deviceId, string deviceModel); + Task GetDeviceState(string deviceId, string deviceModel); + /// /// Sets the On/Off state of a single Govee Device /// @@ -38,7 +43,8 @@ public interface IGoveeApiService /// Device Model Number as string /// /// - public Task ToggleState(string deviceId, string deviceModel, bool on); + Task ToggleState(string deviceId, string deviceModel, bool on); + /// /// Sets the Brightness in Percent of a single Govee Device /// @@ -46,7 +52,8 @@ public interface IGoveeApiService /// Device Model Number as string /// Brightness in Percent as Int /// - public Task SetBrightness(string deviceId, string deviceModel, int value); + Task SetBrightness(string deviceId, string deviceModel, int value); + /// /// Sets a Rgb Color of a single Govee Device /// @@ -54,7 +61,8 @@ public interface IGoveeApiService /// Device Model Number as string /// Rgb Color /// - public Task SetColor(string deviceId, string deviceModel, RgbColor color); + Task SetColor(string deviceId, string deviceModel, RgbColor color); + /// /// Sets the Color Temperature of a single Govee Device /// @@ -62,6 +70,5 @@ public interface IGoveeApiService /// Device Model Number as string /// Color Temp in Kelvin as Int /// - public Task SetColorTemp(string deviceId, string deviceModel, int value); - + Task SetColorTemp(string deviceId, string deviceModel, int value); } \ No newline at end of file diff --git a/GoveeCSharpConnector/Interfaces/IGoveeService.cs b/GoveeCSharpConnector/Interfaces/IGoveeService.cs new file mode 100644 index 0000000..4dfc4a3 --- /dev/null +++ b/GoveeCSharpConnector/Interfaces/IGoveeService.cs @@ -0,0 +1,62 @@ +using GoveeCSharpConnector.Objects; + +namespace GoveeCSharpConnector.Interfaces; + +public interface IGoveeService +{ + /// + /// Govee Api Key + /// + string GoveeApiKey { get; set; } + + /// + /// Gets a List of Govee Devices + /// + /// If true returns that are available on Api and Lan + /// List of Govee Devices + Task> GetDevices(bool onlyLan = true); + + /// + /// Gets the State of a GoveeDevice + /// + /// GoveeDevice + /// Use Udp Connection instead of the Api + /// + Task GetDeviceState(GoveeDevice goveeDevice, bool useUdp = true); + + /// + /// Sets the On/Off State of the GoveeDevice + /// + /// GoveeDevice + /// + /// Use Udp Connection instead of the Api + /// + Task ToggleState(GoveeDevice goveeDevice, bool on, bool useUdp = true); + + /// + /// Sets the Brightness of the GoveeDevice + /// + /// GoveeDevice + /// Brightness in Percent + /// Use Udp Connection instead of the Api + /// + Task SetBrightness(GoveeDevice goveeDevice, int value, bool useUdp = true); + + /// + /// Sets the Color of the GoveeDevice + /// + /// GoveeDevice + /// RgBColor + /// Use Udp Connection instead of the Api + /// + Task SetColor(GoveeDevice goveeDevice, RgbColor color, bool useUdp = true); + + /// + /// Sets the Color Temperature in Kelvin for the GoveeDevice + /// + /// GoveeDevice + /// Color Temp in Kelvin + /// Use Udp Connection instead of the Api + /// + Task SetColorTemp(GoveeDevice goveeDevice, int value, bool useUdp = true); +} \ No newline at end of file diff --git a/GoveeCSharpConnector/Interfaces/IGoveeUdpService.cs b/GoveeCSharpConnector/Interfaces/IGoveeUdpService.cs index f848ae5..2c64db2 100644 --- a/GoveeCSharpConnector/Interfaces/IGoveeUdpService.cs +++ b/GoveeCSharpConnector/Interfaces/IGoveeUdpService.cs @@ -49,6 +49,15 @@ public interface IGoveeUdpService /// Port of the Device. Standard 4003 /// Task SetColor(string deviceAddress, RgbColor color, int uniCastPort = 4003); + + /// + /// Sets the ColorTemp of the Device + /// + /// Ip Address of the Device + /// + /// Port of the Device. Standard 4003 + /// + Task SetColorTemp(string deviceAddress, int colorTempInKelvin, int uniCastPort = 4003); /// /// Starts the Udp Listener /// diff --git a/GoveeCSharpConnector/Objects/GoveeDevice.cs b/GoveeCSharpConnector/Objects/GoveeDevice.cs new file mode 100644 index 0000000..55a9760 --- /dev/null +++ b/GoveeCSharpConnector/Objects/GoveeDevice.cs @@ -0,0 +1,9 @@ +namespace GoveeCSharpConnector.Objects; + +public class GoveeDevice +{ + public string DeviceId { get; set; } + public string Model { get; set; } + public string DeviceName { get; set; } + public string Address { get; set; } +} \ No newline at end of file diff --git a/GoveeCSharpConnector/Objects/GoveeState.cs b/GoveeCSharpConnector/Objects/GoveeState.cs new file mode 100644 index 0000000..7c1acc5 --- /dev/null +++ b/GoveeCSharpConnector/Objects/GoveeState.cs @@ -0,0 +1,11 @@ +using GoveeCSharpConnector.Enums; + +namespace GoveeCSharpConnector.Objects; + +public class GoveeState +{ + public PowerState State { get; set; } + public int Brightness { get; set; } + public RgbColor Color { get; set; } + public int ColorTempInKelvin { get; set; } +} \ No newline at end of file diff --git a/GoveeCSharpConnector/Objects/Properties.cs b/GoveeCSharpConnector/Objects/Properties.cs index 1d23366..7ecd558 100644 --- a/GoveeCSharpConnector/Objects/Properties.cs +++ b/GoveeCSharpConnector/Objects/Properties.cs @@ -7,6 +7,6 @@ public class Properties public bool Online { get; set; } public PowerState PowerState { get; set; } public int Brightness { get; set; } - public int? ColorTemp { get; set; } + public int ColorTemp { get; set; } public RgbColor Color { get; set; } } \ No newline at end of file diff --git a/GoveeCSharpConnector/Services/GoveeService.cs b/GoveeCSharpConnector/Services/GoveeService.cs new file mode 100644 index 0000000..7a0c046 --- /dev/null +++ b/GoveeCSharpConnector/Services/GoveeService.cs @@ -0,0 +1,100 @@ +using GoveeCSharpConnector.Interfaces; +using GoveeCSharpConnector.Objects; + +namespace GoveeCSharpConnector.Services; + +public class GoveeService : IGoveeService +{ + public string GoveeApiKey { get; set; } + + private readonly IGoveeApiService _apiService; + private readonly IGoveeUdpService _udpService; + + public GoveeService(IGoveeApiService apiService,IGoveeUdpService udpService) + { + _apiService = apiService ?? throw new ArgumentNullException(nameof(apiService)); + _udpService = udpService ?? throw new ArgumentNullException(nameof(udpService)); + } + public async Task> GetDevices(bool onlyLan = true) + { + if (string.IsNullOrWhiteSpace(GoveeApiKey)) throw new Exception("No Govee Api Key Set!"); + var apiDevices = await _apiService.GetDevices(); + var devices = apiDevices.Select(apiDevice => new GoveeDevice() { DeviceId = apiDevice.DeviceId, DeviceName = apiDevice.DeviceName, Model = apiDevice.Model, Address = "onlyAvailableOnUdpRequest" }).ToList(); + if (!onlyLan) + return devices; + + if (!_udpService.IsListening()) + _udpService.StartUdpListener(); + + var udpDevices = await _udpService.GetDevices(); + + var combinedDevices = (from goveeDevice in devices let matchingDevice = udpDevices.FirstOrDefault(x => x.device == goveeDevice.DeviceId) + where matchingDevice is not null select + new GoveeDevice { DeviceId = goveeDevice.DeviceId, DeviceName = goveeDevice.DeviceName, Model = goveeDevice.Model, Address = matchingDevice.ip }).ToList(); + + return combinedDevices; + } + + public async Task GetDeviceState(GoveeDevice goveeDevice, bool useUdp = true) + { + if (useUdp) + { + if (!_udpService.IsListening()) + _udpService.StartUdpListener(); + if (string.IsNullOrWhiteSpace(goveeDevice.Address)) throw new Exception("Device not available via Udp/Lan"); + var udpState = await _udpService.GetState(goveeDevice.Address); + return new GoveeState() { State = udpState.onOff, Brightness = udpState.brightness, Color = udpState.color, ColorTempInKelvin = udpState.colorTempInKelvin }; + } + if (string.IsNullOrWhiteSpace(GoveeApiKey)) throw new Exception("No Govee Api Key Set!"); + var apiState = await _apiService.GetDeviceState(goveeDevice.DeviceId, goveeDevice.Model); + return new GoveeState{State = apiState.Properties.PowerState, Brightness = apiState.Properties.Brightness, Color = apiState.Properties.Color, ColorTempInKelvin = apiState.Properties.ColorTemp}; + } + + public async Task ToggleState(GoveeDevice goveeDevice, bool on, bool useUdp = true) + { + if (useUdp) + { + if (string.IsNullOrWhiteSpace(goveeDevice.Address)) throw new Exception("Device not available via Udp/Lan"); + await _udpService.ToggleDevice(goveeDevice.Address, on); + return; + } + if (string.IsNullOrWhiteSpace(GoveeApiKey)) throw new Exception("No Govee Api Key Set!"); + await _apiService.ToggleState(goveeDevice.DeviceId, goveeDevice.Model, on); + } + + public async Task SetBrightness(GoveeDevice goveeDevice, int value, bool useUdp = true) + { + if (useUdp) + { + if (string.IsNullOrWhiteSpace(goveeDevice.Address)) throw new Exception("Device not available via Udp/Lan"); + await _udpService.SetBrightness(goveeDevice.Address, value); + return; + } + if (string.IsNullOrWhiteSpace(GoveeApiKey)) throw new Exception("No Govee Api Key Set!"); + await _apiService.SetBrightness(goveeDevice.DeviceId, goveeDevice.Model, value); + } + + public async Task SetColor(GoveeDevice goveeDevice, RgbColor color, bool useUdp = true) + { + if (useUdp) + { + if (string.IsNullOrWhiteSpace(goveeDevice.Address)) throw new Exception("Device not available via Udp/Lan"); + await _udpService.SetColor(goveeDevice.Address, color); + return; + } + if (string.IsNullOrWhiteSpace(GoveeApiKey)) throw new Exception("No Govee Api Key Set!"); + await _apiService.SetColor(goveeDevice.DeviceId, goveeDevice.Model, color); + } + + public async Task SetColorTemp(GoveeDevice goveeDevice, int value, bool useUdp = true) + { + if (useUdp) + { + if (string.IsNullOrWhiteSpace(goveeDevice.Address)) throw new Exception("Device not available via Udp/Lan"); + await _udpService.SetColorTemp(goveeDevice.Address, value); + return; + } + if (string.IsNullOrWhiteSpace(GoveeApiKey)) throw new Exception("No Govee Api Key Set!"); + await _apiService.SetColorTemp(goveeDevice.DeviceId, goveeDevice.Model, value); + } +} \ No newline at end of file diff --git a/GoveeCSharpConnector/Services/GoveeUdpService.cs b/GoveeCSharpConnector/Services/GoveeUdpService.cs index 7c9ffb1..797f334 100644 --- a/GoveeCSharpConnector/Services/GoveeUdpService.cs +++ b/GoveeCSharpConnector/Services/GoveeUdpService.cs @@ -38,9 +38,9 @@ public class GoveeUdpService : IGoveeUdpService try { // Build Message - var message = new GoveeUdpMessage() + var message = new GoveeUdpMessage { - msg = new msg() + msg = new msg { cmd = "scan", data = new { account_topic = "reserve" } @@ -76,9 +76,9 @@ public class GoveeUdpService : IGoveeUdpService try { // Build Message - var message = new GoveeUdpMessage() + var message = new GoveeUdpMessage { - msg = new msg() + msg = new msg { cmd = "devStatus", data = new { } @@ -107,9 +107,9 @@ public class GoveeUdpService : IGoveeUdpService try { // Build Message - var message = new GoveeUdpMessage() + var message = new GoveeUdpMessage { - msg = new msg() + msg = new msg { cmd = "turn", data = new { value = on ? 1 : 0 } @@ -131,9 +131,9 @@ public class GoveeUdpService : IGoveeUdpService try { // Build Message - var message = new GoveeUdpMessage() + var message = new GoveeUdpMessage { - msg = new msg() + msg = new msg { cmd = "brightness", data = new { value = brightness } @@ -155,9 +155,9 @@ public class GoveeUdpService : IGoveeUdpService try { // Build Message - var message = new GoveeUdpMessage() + var message = new GoveeUdpMessage { - msg = new msg() + msg = new msg { cmd = "colorwc", data = new @@ -173,7 +173,6 @@ public class GoveeUdpService : IGoveeUdpService }; // Send Message SendUdpMessage(JsonSerializer.Serialize(message), deviceAddress, uniCastPort); - } catch (Exception e) { @@ -181,6 +180,39 @@ public class GoveeUdpService : IGoveeUdpService throw; } } + + public async Task SetColorTemp(string deviceAddress, int colorTempInKelvin, int uniCastPort = 4003) + { + try + { + // Build Message + var message = new GoveeUdpMessage + { + msg = new msg + { + cmd = "colorwc", + data = new + { + color = new + { + r = 0, + g = 0, + b = 0 + }, + colorTempInKelvin = colorTempInKelvin + } + } + }; + // Send Message + SendUdpMessage(JsonSerializer.Serialize(message), deviceAddress, uniCastPort); + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + } + /// public async void StartUdpListener() { diff --git a/README.md b/README.md index f15e61e..a16445f 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ ![netStandard2.0](https://img.shields.io/badge/.NET%20Standard-2.0-blueviolet) [![Nuget](https://img.shields.io/nuget/v/GoveeCSharpConnector?cacheSeconds=50)](https://www.nuget.org/packages/GoveeCSharpConnector/) + # About Simple .net Library to interface with Govee Smart Lights via their Web Api or Lan Udp connection.