michielpost / Q42.HueApi

C# helper library to talk to the Philips Hue bridge
MIT License
411 stars 114 forks source link

Enhancing UpdateLightExtensions to support Dimming and DimmingDelta #303

Closed AleRoe closed 1 year ago

AleRoe commented 1 year ago

Hi Michael,

I took the liberty to extend the UpdateLightExtensions with two new static methods: public static T SetBrightnessDelta<T>(this T lightCommand, DeltaAction action, int brightnessDelta) where T : IUpdateDimmingDelta

public static T SetBrightness<T>(this T lightCommand, int brightness) where T : IUpdateDimming

As I can't create a new branch / pull request, please see code below. Would be great if you could incorporate this in the next release.

Add new interfaces:

namespace HueApi.Models.Requests.Interface
{
  public interface IUpdateDimming
  {
    public Dimming? Dimming { get; set; }
  }
}

namespace HueApi.Models.Requests.Interface
{
  public interface IUpdateDimmingDelta
  {
    public DimmingDelta? DimmingDelta { get; set; }
  }
}

Have UpdateLight() implement new interfaces:

public class UpdateLight : BaseResourceRequest, IUpdateColor, IUpdateColorTemperature, IUpdateOn, IUpdateDimmingDelta, IUpdateDimming 
{
....
}

Add to UpdateLightExtensions.cs:


    /// <summary>
    /// Helper to create DimmingDelta command
    /// </summary>
    /// <param name="lightCommand"></param>
    /// <param name="action"></param>
    /// <param name="brightnessDelta"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentNullException"></exception>
    /// <exception cref="ArgumentOutOfRangeException"></exception>
    public static T SetBrightnessDelta<T>(this T lightCommand, DeltaAction action, int brightnessDelta) where T : IUpdateDimmingDelta
    {
      if (lightCommand == null)
        throw new ArgumentNullException(nameof(lightCommand));

      if (!(1 <= brightnessDelta && brightnessDelta <= 100))
        throw new ArgumentOutOfRangeException(nameof(brightnessDelta),"Value must be between 1 and 100");

      lightCommand.DimmingDelta = new DimmingDelta
      {
        Action = action,
        BrightnessDelta = brightnessDelta
      };
      return lightCommand;
    }

    /// <summary>
    /// Helper to create Dimming command
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="lightCommand"></param>
    /// <param name="brightness"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentNullException"></exception>
    /// <exception cref="ArgumentOutOfRangeException"></exception>
    public static T SetBrightness<T>(this T lightCommand, int brightness) where T : IUpdateDimming
    {
      if (lightCommand == null)
        throw new ArgumentNullException(nameof(lightCommand));

      if (!(0 <= brightness && brightness <= 100))
        throw new ArgumentOutOfRangeException(nameof(brightness), "Value must be between 0 and 100");

      lightCommand.Dimming = new Dimming
      {
        Brightness = brightness
      };
      return lightCommand;
    }

Add Unittests to LightTests.cs:

    [TestMethod]
    public async Task SetBrightnessDeltaDown()
    {
      var all = await localHueClient.GetLightsAsync();
      var id = all.Data.First().Id;

      var req = new UpdateLight().SetBrightnessDelta(DeltaAction.down, 10);
      var result = await localHueClient.UpdateLightAsync(id, req);

      Assert.IsNotNull(result);
      Assert.IsFalse(result.HasErrors);

      Assert.IsTrue(result.Data.Count == 1);
      Assert.AreEqual(id, result.Data.First().Rid);
    }

    [TestMethod]
    public async Task SetBrightnessDeltaUp()
    {
      var all = await localHueClient.GetLightsAsync();
      var id = all.Data.First().Id;

      var req = new UpdateLight().SetBrightnessDelta(DeltaAction.up, 10);
      var result = await localHueClient.UpdateLightAsync(id, req);

      Assert.IsNotNull(result);
      Assert.IsFalse(result.HasErrors);

      Assert.IsTrue(result.Data.Count == 1);
      Assert.AreEqual(id, result.Data.First().Rid);
    }

    [TestMethod]
    public async Task SetBrightness()
    {
      var all = await localHueClient.GetLightsAsync();
      var id = all.Data.First().Id;

      var req = new UpdateLight().SetBrightness(50);
      var result = await localHueClient.UpdateLightAsync(id, req);

      Assert.IsNotNull(result);
      Assert.IsFalse(result.HasErrors);

      Assert.IsTrue(result.Data.Count == 1);
      Assert.AreEqual(id, result.Data.First().Rid);
    }

Kind regards Alexander

AleRoe commented 1 year ago

Small addition: By updating the class UpdateGroupedLight to implement the two new interfaces, the extensions should then also work.

michielpost commented 1 year ago

Thanks for the contribution. I added the code to the project and it's released with version 0.10.0.

Next time, you can fork this project, then make the changes on your own fork and create a PR to this project.

AleRoe commented 1 year ago

Hi Michiel, thanks for adding the code, much appreciated! Just tested with the new version and works as expected.

I did notice a small error in my code though : Dimming.Brightness is of type double. The method signature for public static T SetBrightness<T>(this T lightCommand, int brightness) where T : IUpdateDimming mistakenly takes an int for the brightness parameter. While this does not break, it might be worth fixing at some time. No need for an immediate fix. Sorry for the inconvenience!

I will definitely give forking a try for further enhancements!

Closing this issue as resolved. Kind regards, Alexander

michielpost commented 1 year ago

I'll change it to a double in the next version. I'm also going to change DimmingDelta.BrightnessDelta from an integer to a double. In the Hue Api documentation these fields are indicated as number instead of integer. So i will also change the SetBrightnessDelta extension method.