Compare commits

..

6 Commits

Author SHA1 Message Date
76ccf20c30 Fixed UdpDeviceList Pick
Fixed UdpListener Start
2024-02-03 12:23:34 +01:00
a069133a68 Set Api Key (#4)
* 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

* Set Api Key on Request
2024-02-03 01:25:44 +01:00
bb01b3342d 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
2024-02-03 00:57:33 +01:00
602926c43e Create nuget.yml
Add Nuget Action
2024-02-02 19:21:45 +01:00
2eef997c6e Update README.md (#2) 2024-02-02 19:06:51 +01:00
bb9364c491 Dev (#1)
* Delete .gitignore

* Added Readme, Added Nuget Infos in Project
2024-02-02 19:05:57 +01:00
33 changed files with 534 additions and 636 deletions

View File

@ -1,106 +1,27 @@
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json name: Release to NuGet
name: publish
on: on:
workflow_dispatch: # Allow running the workflow manually from the GitHub UI
push: push:
branches: branches:
- 'main' # Run the workflow when pushing to the main branch - master # Default release branch
pull_request: pull_request:
branches: branches:
- '*' # Run the workflow for all pull requests - master # Run the workflow for all pull requests on Branch Master
release:
types:
- published # Run the workflow when a new GitHub release is published
env:
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
DOTNET_NOLOGO: true
NuGetDirectory: ${{ github.workspace}}/nuget
defaults:
run:
shell: pwsh
jobs: jobs:
create_nuget: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 5
steps: steps:
- uses: actions/checkout@v3 - name: Checkout
with: uses: actions/checkout@v4.1.1
fetch-depth: 0 # Get all history to allow automatic versioning using MinVer - name: Setup .NET SDK
uses: actions/setup-dotnet@v1.5
# Install the .NET SDK indicated in the global.json file - name: Build
- name: Setup .NET run: dotnet build -c Release
uses: actions/setup-dotnet@v4 - name: Test
run: dotnet test -c Release --no-build
# Create the NuGet package in the folder from the environment variable NuGetDirectory - name: Pack nugets
- run: dotnet pack --configuration Release --output ${{ env.NuGetDirectory }} run: dotnet pack -c Release --no-build --output .
- name: Push to NuGet
# Publish the NuGet package as an artifact, so they can be used in the following jobs run: dotnet nuget push "*.nupkg" --api-key ${{secrets.NUGET_KEY}} --source https://api.nuget.org/v3/index.json
- uses: actions/upload-artifact@v3
with:
name: nuget
if-no-files-found: error
retention-days: 7
path: ${{ env.NuGetDirectory }}/*.nupkg
validate_nuget:
runs-on: ubuntu-latest
needs: [ create_nuget ]
steps:
# Install the .NET SDK indicated in the global.json file
- name: Setup .NET
uses: actions/setup-dotnet@v4
# Download the NuGet package created in the previous job
- uses: actions/download-artifact@v3
with:
name: nuget
path: ${{ env.NuGetDirectory }}
- name: Install nuget validator
run: dotnet tool update Meziantou.Framework.NuGetPackageValidation.Tool --global
# Validate metadata and content of the NuGet package
# https://www.nuget.org/packages/Meziantou.Framework.NuGetPackageValidation.Tool#readme-body-tab
# If some rules are not applicable, you can disable them
# using the --excluded-rules or --excluded-rule-ids option
- name: Validate package
run: meziantou.validate-nuget-package (Get-ChildItem "${{ env.NuGetDirectory }}/*.nupkg")
run_test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup .NET
uses: actions/setup-dotnet@v4
- name: Run tests
run: dotnet test --configuration Release
deploy:
# Publish only when creating a GitHub Release
# https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository
# You can update this logic if you want to manage releases differently
if: github.event_name == 'release'
runs-on: ubuntu-latest
needs: [ validate_nuget, run_test ]
steps:
# Download the NuGet package created in the previous job
- uses: actions/download-artifact@v3
with:
name: nuget
path: ${{ env.NuGetDirectory }}
# Install the .NET SDK indicated in the global.json file
- name: Setup .NET Core
uses: actions/setup-dotnet@v4
# Publish all NuGet packages to NuGet.org
# Use --skip-duplicate to prevent errors if a package with the same version already exists.
# If you retry a failed workflow, already published packages will be skipped without error.
- name: Publish NuGet package
run: |
foreach($file in (Get-ChildItem "${{ env.NuGetDirectory }}" -Recurse -Include *.nupkg)) {
dotnet nuget push $file --api-key "${{ secrets.NUGET_KEY }}" --source https://api.nuget.org/v3/index.json --skip-duplicate
}

View File

@ -2,6 +2,8 @@
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GoveeCSharpConnector", "GoveeCSharpConnector\GoveeCSharpConnector.csproj", "{EDF67B3A-9EBF-4C76-92E2-0AACD6B8081B}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GoveeCSharpConnector", "GoveeCSharpConnector\GoveeCSharpConnector.csproj", "{EDF67B3A-9EBF-4C76-92E2-0AACD6B8081B}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GoveeCsharpConnector.Example", "GoveeCsharpConnector.Example\GoveeCsharpConnector.Example.csproj", "{E487B84B-F619-430A-A0D3-80D44FE9EE3F}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -12,5 +14,9 @@ Global
{EDF67B3A-9EBF-4C76-92E2-0AACD6B8081B}.Debug|Any CPU.Build.0 = Debug|Any CPU {EDF67B3A-9EBF-4C76-92E2-0AACD6B8081B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EDF67B3A-9EBF-4C76-92E2-0AACD6B8081B}.Release|Any CPU.ActiveCfg = Release|Any CPU {EDF67B3A-9EBF-4C76-92E2-0AACD6B8081B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EDF67B3A-9EBF-4C76-92E2-0AACD6B8081B}.Release|Any CPU.Build.0 = Release|Any CPU {EDF67B3A-9EBF-4C76-92E2-0AACD6B8081B}.Release|Any CPU.Build.0 = Release|Any CPU
{E487B84B-F619-430A-A0D3-80D44FE9EE3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E487B84B-F619-430A-A0D3-80D44FE9EE3F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E487B84B-F619-430A-A0D3-80D44FE9EE3F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E487B84B-F619-430A-A0D3-80D44FE9EE3F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

View File

@ -1,3 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=Govee/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Govee/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
<s:Boolean x:Key="/Default/UserDictionary/Words/=reauired/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@ -13,7 +13,6 @@
<RepositoryUrl>https://github.com/Locxion/GoveeCSharpConnector</RepositoryUrl> <RepositoryUrl>https://github.com/Locxion/GoveeCSharpConnector</RepositoryUrl>
<PackageLicenseUrl>https://github.com/Locxion/GoveeCSharpConnector/blob/main/LICENSE</PackageLicenseUrl> <PackageLicenseUrl>https://github.com/Locxion/GoveeCSharpConnector/blob/main/LICENSE</PackageLicenseUrl>
<Version>1.1.2</Version> <Version>1.1.2</Version>
<PackageReadmeFile>../README.md</PackageReadmeFile>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="System.Net.Http.Json" Version="8.0.0" /> <PackageReference Include="System.Net.Http.Json" Version="8.0.0" />

View File

@ -1,9 +1,8 @@
using GoveeCSharpConnector.Objects; using GoveeCSharpConnector.Objects;
using GoveeCSharpConnector.Objects.Misc;
namespace GoveeCSharpConnector.Interfaces; namespace GoveeCSharpConnector.Interfaces;
public interface IGoveeHttpService public interface IGoveeApiService
{ {
/// <summary> /// <summary>
/// Sets the required Api Key for the Govee Api. /// Sets the required Api Key for the Govee Api.
@ -11,27 +10,32 @@ public interface IGoveeHttpService
/// </summary> /// </summary>
/// <param name="apiKey">Api Key as String</param> /// <param name="apiKey">Api Key as String</param>
void SetApiKey(string apiKey); void SetApiKey(string apiKey);
/// <summary> /// <summary>
/// Returns current set Govee Api Key /// Returns current set Govee Api Key
/// </summary> /// </summary>
/// <returns>Govee Api Key as String</returns> /// <returns>Govee Api Key as String</returns>
string GetApiKey(); string GetApiKey();
/// <summary> /// <summary>
/// Removes the Set Api Key and resets the HTTP Header /// Removes the Set Api Key and resets the HTTP Header
/// </summary> /// </summary>
void RemoveApiKey(); void RemoveApiKey();
/// <summary> /// <summary>
/// Requests all Devices registered to Api Key Govee Account /// Requests all Devices registered to Api Key Govee Account
/// </summary> /// </summary>
/// <returns>List of GoveeHttpDevices</returns> /// <returns>List of GoveeApiDevices</returns>
Task<ServiceResponse<List<GoveeHttpDevice>>> GetDevices(); Task<List<GoveeApiDevice>> GetDevices();
/// <summary> /// <summary>
/// Requests the State of a single Govee Device /// Requests the State of a single Govee Device
/// </summary> /// </summary>
/// <param name="deviceId">Device Id Guid as string</param> /// <param name="deviceId">Device Id Guid as string</param>
/// <param name="deviceModel">Device Model Number as string</param> /// <param name="deviceModel">Device Model Number as string</param>
/// <returns>GoveeHttpState Object</returns> /// <returns>GoveeApiStat Object</returns>
Task<ServiceResponse<GoveeHttpState>> GetDeviceState(string deviceId, string deviceModel); Task<GoveeApiState> GetDeviceState(string deviceId, string deviceModel);
/// <summary> /// <summary>
/// Sets the On/Off state of a single Govee Device /// Sets the On/Off state of a single Govee Device
/// </summary> /// </summary>
@ -39,7 +43,17 @@ public interface IGoveeHttpService
/// <param name="deviceModel">Device Model Number as string</param> /// <param name="deviceModel">Device Model Number as string</param>
/// <param name="on"></param> /// <param name="on"></param>
/// <returns></returns> /// <returns></returns>
Task<ServiceResponse<bool>> SetOnOff(string deviceId, string deviceModel, bool on); Task ToggleState(string deviceId, string deviceModel, bool on);
/// <summary>
/// Sets the Brightness in Percent of a single Govee Device
/// </summary>
/// <param name="deviceId">Device Id Guid as string</param>
/// <param name="deviceModel">Device Model Number as string</param>
/// <param name="value">Brightness in Percent as Int</param>
/// <returns></returns>
Task SetBrightness(string deviceId, string deviceModel, int value);
/// <summary> /// <summary>
/// Sets a Rgb Color of a single Govee Device /// Sets a Rgb Color of a single Govee Device
/// </summary> /// </summary>
@ -47,7 +61,8 @@ public interface IGoveeHttpService
/// <param name="deviceModel">Device Model Number as string</param> /// <param name="deviceModel">Device Model Number as string</param>
/// <param name="color">Rgb Color</param> /// <param name="color">Rgb Color</param>
/// <returns></returns> /// <returns></returns>
Task<ServiceResponse<bool>> SetColor(string deviceId, string deviceModel, RgbColor color); Task SetColor(string deviceId, string deviceModel, RgbColor color);
/// <summary> /// <summary>
/// Sets the Color Temperature of a single Govee Device /// Sets the Color Temperature of a single Govee Device
/// </summary> /// </summary>
@ -55,37 +70,5 @@ public interface IGoveeHttpService
/// <param name="deviceModel">Device Model Number as string</param> /// <param name="deviceModel">Device Model Number as string</param>
/// <param name="value">Color Temp in Kelvin as Int</param> /// <param name="value">Color Temp in Kelvin as Int</param>
/// <returns></returns> /// <returns></returns>
Task<ServiceResponse<bool>> SetColorTemp(string deviceId, string deviceModel, int value); Task SetColorTemp(string deviceId, string deviceModel, int value);
/// <summary>
/// Sets the Brightness of a single Govee Device
/// </summary>
/// <param name="deviceId">Device Id Guid as string</param>
/// <param name="deviceModel">Device Model Number as string</param>
/// <param name="value">Value 1-100</param>
/// <returns></returns>
Task<ServiceResponse<bool>> SetBrightness(string deviceId, string deviceModel, int value);
/// <summary>
/// Gets a List of all available Govee Scenes for the Device
/// </summary>
/// <param name="deviceId">Device Id Guid as string</param>
/// <param name="deviceModel">Device Model Number as string</param>
/// <returns></returns>
Task<ServiceResponse<List<GoveeScene>>> GetScenes(string deviceId, string deviceModel);
/// <summary>
/// Sets the LightScene of a single Govee Device
/// </summary>
/// <param name="deviceId">Device Id Guid as string</param>
/// <param name="deviceModel">Device Model Number as string</param>
/// <param name="sceneValue">Number of the Scene</param>
/// <returns></returns>
Task<ServiceResponse<bool>> SetLightScene(string deviceId, string deviceModel, int sceneValue);
/// <summary>
/// Sets the DiyScene of a single Govee Device
/// </summary>
/// <param name="deviceId">Device Id Guid as string</param>
/// <param name="deviceModel">Device Model Number as string</param>
/// <param name="sceneValue">Number of the Scene</param>
/// <returns></returns>
Task<ServiceResponse<bool>> SetDiyScene(string deviceId, string deviceModel, int sceneValue);
} }

View File

@ -12,7 +12,7 @@ public interface IGoveeUdpService
/// <summary> /// <summary>
/// Sends a Scan Command via Udp Multicast. /// Sends a Scan Command via Udp Multicast.
/// </summary> /// </summary>
/// <param name="timeout">Standard 200ms</param> /// <param name="timeout">Standard 250ms</param>
/// <returns>List of GoveeUdpDevices</returns> /// <returns>List of GoveeUdpDevices</returns>
Task<List<GoveeUdpDevice>> GetDevices(TimeSpan? timeout = null); Task<List<GoveeUdpDevice>> GetDevices(TimeSpan? timeout = null);
@ -21,7 +21,7 @@ public interface IGoveeUdpService
/// </summary> /// </summary>
/// <param name="deviceAddress">Ip Address of the Device</param> /// <param name="deviceAddress">Ip Address of the Device</param>
/// <param name="uniCastPort">Port of the Device. Standard 4003</param> /// <param name="uniCastPort">Port of the Device. Standard 4003</param>
/// <param name="timeout">Standard 200ms</param> /// <param name="timeout">Standard 250ms</param>
/// <returns></returns> /// <returns></returns>
Task<GoveeUdpState> GetState(string deviceAddress, int uniCastPort = 4003, TimeSpan? timeout = null); Task<GoveeUdpState> GetState(string deviceAddress, int uniCastPort = 4003, TimeSpan? timeout = null);

View File

@ -0,0 +1,7 @@
namespace GoveeCSharpConnector.Objects;
public class ApiResponse
{
public string? Message { get; set; }
public int Code { get; set; }
}

View File

@ -0,0 +1,8 @@
using System.Collections.Generic;
namespace GoveeCSharpConnector.Objects;
public class Data
{
public List<GoveeApiDevice> Devices { get; set; }
}

View File

@ -0,0 +1,14 @@
namespace GoveeCSharpConnector.Objects;
public class GoveeApiCommand
{
public string Device { get; set; }
public string Model { get; set; }
public Command Cmd { get; set; }
}
public class Command
{
public string Name { get; set; }
public object Value { get; set; }
}

View File

@ -0,0 +1,17 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace GoveeCSharpConnector.Objects;
public class GoveeApiDevice
{
[JsonPropertyName("device")]
public string DeviceId { get; set; }
public string Model { get; set; }
public string DeviceName { get; set; }
public bool Controllable { get; set; }
public bool Retrievable { get; set; }
[JsonPropertyName("supportCmds")]
public List<string> SupportedCommands { get; set; }
public Properties Properties { get; set; }
}

View File

@ -0,0 +1,16 @@
using System.Text.Json.Serialization;
namespace GoveeCSharpConnector.Objects;
public class GoveeApiState
{
[JsonPropertyName("device")]
public string DeviceId { get; set; }
public string Model { get; set; }
public string Name { get; set; }
[JsonIgnore]
public Properties Properties { get; set; }
}

View File

@ -1,14 +0,0 @@
using System.Text.Json.Serialization;
using GoveeCSharpConnector.Objects.Misc;
namespace GoveeCSharpConnector.Objects;
public class GoveeHttpDevice
{
[JsonPropertyName("sku")]
public string Model { get; set; }
[JsonPropertyName("device")]
public string Device { get; set; }
[JsonPropertyName("capabilities")]
public List<Capability> Capabilities { get; set; }
}

View File

@ -1,16 +0,0 @@
using System.Text.Json.Serialization;
using GoveeCSharpConnector.Objects.Misc;
namespace GoveeCSharpConnector.Objects;
public class GoveeHttpState
{
[JsonPropertyName("requestId")]
public string RequestId { get; set; }
[JsonPropertyName("msg")]
public string Msg { get; set; }
[JsonPropertyName("code")]
public long Code { get; set; }
[JsonPropertyName("payload")]
public Payload Payload { get; set; }
}

View File

@ -0,0 +1,6 @@
namespace GoveeCSharpConnector.Objects;
public class GoveeResponse : ApiResponse
{
public Data Data { get; set; }
}

View File

@ -1,13 +0,0 @@
using System.Text.Json.Serialization;
using GoveeCSharpConnector.Objects.Misc;
namespace GoveeCSharpConnector.Objects;
public class GoveeScene
{
[JsonPropertyName("name")]
public string Name { get; set; }
[JsonPropertyName("value")]
public SceneValue SceneValue { get; set; }
}

View File

@ -1,13 +0,0 @@
using System.Text.Json.Serialization;
namespace GoveeCSharpConnector.Objects.Misc;
public class ApiResponse
{
[JsonPropertyName("code")]
public int Code { get; set; }
[JsonPropertyName("message")]
public string Message { get; set; }
[JsonPropertyName("data")]
public List<object> Data { get; set; }
}

View File

@ -1,13 +0,0 @@
using System.Text.Json.Serialization;
namespace GoveeCSharpConnector.Objects.Misc;
public class Capability
{
[JsonPropertyName("type")]
public string Type { get; set; }
[JsonPropertyName("instance")]
public string Instance { get; set; }
[JsonPropertyName("state")]
public State State { get; set; }
}

View File

@ -1,21 +0,0 @@
using System.Text.Json.Serialization;
namespace GoveeCSharpConnector.Objects.Misc;
public class Field
{
[JsonPropertyName("fieldName")]
public string FieldName { get; set; }
[JsonPropertyName("dataType")]
public string DataType { get; set; }
[JsonPropertyName("options")]
public List<Option> Options { get; set; }
[JsonPropertyName("required")]
public bool Required { get; set; }
[JsonPropertyName("range")]
public Range Range { get; set; }
[JsonPropertyName("unit")]
public string Unit { get; set; }
[JsonPropertyName("reauired")]
public bool? Reauired { get; set; }
}

View File

@ -1,11 +0,0 @@
using System.Text.Json.Serialization;
namespace GoveeCSharpConnector.Objects.Misc;
public class Option
{
[JsonPropertyName("name")]
public string Name { get; set; }
[JsonPropertyName("value")]
public int Value { get; set; }
}

View File

@ -1,17 +0,0 @@
using System.Text.Json.Serialization;
namespace GoveeCSharpConnector.Objects.Misc;
public class Parameters
{
[JsonPropertyName("dataType")]
public string DataType { get; set; }
[JsonPropertyName("options")]
public List<Option> Options { get; set; }
[JsonPropertyName("unit")]
public string Unit { get; set; }
[JsonPropertyName("range")]
public Range Range { get; set; }
[JsonPropertyName("fields")]
public List<Field> Fields { get; set; }
}

View File

@ -1,13 +0,0 @@
using System.Text.Json.Serialization;
namespace GoveeCSharpConnector.Objects.Misc;
public class Payload
{
[JsonPropertyName("sku")]
public string Model { get; set; }
[JsonPropertyName("device")]
public string Device { get; set; }
[JsonPropertyName("capabilities")]
public List<Capability> Capabilities { get; set; }
}

View File

@ -1,13 +0,0 @@
using System.Text.Json.Serialization;
namespace GoveeCSharpConnector.Objects.Misc;
public class Range
{
[JsonPropertyName("min")]
public int Min { get; set; }
[JsonPropertyName("max")]
public int Max { get; set; }
[JsonPropertyName("precision")]
public int Precision { get; set; }
}

View File

@ -1,12 +0,0 @@
using System.Text.Json.Serialization;
namespace GoveeCSharpConnector.Objects.Misc;
public class SceneValue
{
[JsonPropertyName("paramId")]
public long ParamId { get; set; }
[JsonPropertyName("id")]
public long Id { get; set; }
}

View File

@ -1,8 +0,0 @@
namespace GoveeCSharpConnector.Objects.Misc;
public class ServiceResponse<T>
{
public T? Data { get; set; }
public bool Success { get; set; } = true;
public string Message { get; set; } = string.Empty;
}

View File

@ -1,9 +0,0 @@
using System.Text.Json.Serialization;
namespace GoveeCSharpConnector.Objects.Misc;
public class State
{
[JsonPropertyName("value")]
public object Value { get; set; }
}

View File

@ -1,18 +1,12 @@
using System.Text.Json.Serialization;
using GoveeCSharpConnector.Enums; using GoveeCSharpConnector.Enums;
namespace GoveeCSharpConnector.Objects.Misc; namespace GoveeCSharpConnector.Objects;
public class Properties public class Properties
{ {
[JsonPropertyName("online")]
public bool Online { get; set; } public bool Online { get; set; }
[JsonPropertyName("powerState")]
public PowerState PowerState { get; set; } public PowerState PowerState { get; set; }
[JsonPropertyName("brightness")]
public int Brightness { get; set; } public int Brightness { get; set; }
[JsonPropertyName("colorTemp")]
public int ColorTemp { get; set; } public int ColorTemp { get; set; }
[JsonPropertyName("color")]
public RgbColor Color { get; set; } public RgbColor Color { get; set; }
} }

View File

@ -0,0 +1,85 @@
using System.Net.Http.Json;
using System.Text;
using System.Text.Json;
using GoveeCSharpConnector.Interfaces;
using GoveeCSharpConnector.Objects;
namespace GoveeCSharpConnector.Services;
public class GoveeApiService : IGoveeApiService
{
private string _apiKey = string.Empty;
private const string GoveeApiAddress = "https://developer-api.govee.com/v1";
private readonly HttpClient _httpClient = new();
private readonly JsonSerializerOptions? _jsonOptions = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
};
/// <inheritdoc/>
public void SetApiKey(string apiKey)
{
_apiKey = apiKey;
_httpClient.DefaultRequestHeaders.Add("Govee-API-Key", _apiKey);
}
/// <inheritdoc/>
public string GetApiKey()
{
return _apiKey;
}
/// <inheritdoc/>
public void RemoveApiKey()
{
_apiKey = string.Empty;
_httpClient.DefaultRequestHeaders.Remove("Govee-Api-Key");
}
/// <inheritdoc/>
public async Task<List<GoveeApiDevice>> GetDevices()
{
var response = await _httpClient.GetFromJsonAsync<GoveeResponse>($"{GoveeApiAddress}/devices");
return response.Data.Devices;
}
/// <inheritdoc/>
public async Task<GoveeApiState> GetDeviceState(string deviceId, string deviceModel)
{
return await _httpClient.GetFromJsonAsync<GoveeApiState>($"{GoveeApiAddress}/devices/state?device={deviceId}&model={deviceModel}");
}
/// <inheritdoc/>
public async Task ToggleState(string deviceId, string deviceModel, bool on)
{
await SendCommand(deviceId, deviceModel, "turn", on ? "on" : "off");
}
/// <inheritdoc/>
public async Task SetBrightness(string deviceId, string deviceModel, int value)
{
await SendCommand(deviceId, deviceModel, "brightness", value);
}
/// <inheritdoc/>
public async Task SetColor(string deviceId, string deviceModel, RgbColor color)
{
await SendCommand(deviceId, deviceModel, "color", color);
}
/// <inheritdoc/>
public async Task SetColorTemp(string deviceId, string deviceModel, int value)
{
await SendCommand(deviceId, deviceModel, "colorTem", value);
}
private async Task SendCommand(string deviceId, string deviceModel, string command, object commandObject)
{
var commandRequest = new GoveeApiCommand()
{
Device = deviceId,
Model = deviceModel,
Cmd = new Command()
{
Name = command,
Value = commandObject
}
};
var httpContent = new StringContent(JsonSerializer.Serialize(commandRequest, _jsonOptions), Encoding.UTF8, "application/json");
var response = await _httpClient.PutAsync($"{GoveeApiAddress}/devices/control", httpContent);
if (!response.IsSuccessStatusCode)
throw new Exception($"Govee Api Request failed. Status code: {response.StatusCode}, Message: {response.Content}");
}
}

View File

@ -1,306 +0,0 @@
using System.Net.Http.Json;
using System.Text;
using System.Text.Json;
using GoveeCSharpConnector.Interfaces;
using GoveeCSharpConnector.Objects;
using GoveeCSharpConnector.Objects.Misc;
namespace GoveeCSharpConnector.Services;
public class GoveeHttpService : IGoveeHttpService
{
private string _apiKey = string.Empty;
private const string GoveeApiAddress = "https://openapi.api.govee.com";
private const string GoveeDevicesEndpoint = "/router/api/v1/user/devices";
private const string GoveeControlEndpoint = "/router/api/v1/device/control";
private const string GoveeStateEndpoint = "/router/api/v1/device/state";
private const string GoveeScenesEndpoint = "/router/api/v1/device/scenes";
private readonly HttpClient _httpClient = new();
private readonly JsonSerializerOptions? _jsonOptions = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
};
public GoveeHttpService()
{
_httpClient.DefaultRequestHeaders.Add("Content-Type", "application/json");
}
/// <inheritdoc/>
public void SetApiKey(string apiKey)
{
_apiKey = apiKey;
_httpClient.DefaultRequestHeaders.Add("Govee-API-Key", _apiKey);
}
/// <inheritdoc/>
public string GetApiKey()
{
return _apiKey;
}
/// <inheritdoc/>
public void RemoveApiKey()
{
_apiKey = string.Empty;
_httpClient.DefaultRequestHeaders.Remove("Govee-API-Key");
}
/// <inheritdoc/>
public async Task<ServiceResponse<List<GoveeHttpDevice>>> GetDevices()
{
var serviceResponse = new ServiceResponse<List<GoveeHttpDevice>>();
var response = await _httpClient.GetFromJsonAsync<ApiResponse>($"{GoveeApiAddress}{GoveeDevicesEndpoint}");
if (response.Code != 200)
{
if (response.Code == 429)
{
serviceResponse.Success = false;
serviceResponse.Message = "Api Limit reached! 10000/Account/Day";
return serviceResponse;
}
serviceResponse.Success = false;
serviceResponse.Message = response.Message;
return serviceResponse;
}
var allDevices = response.Data.OfType<GoveeHttpDevice>().ToList();
var devices = (from device in allDevices where device.Capabilities.Exists(x => x.Type == "devices.capabilities.on_off")
where device.Capabilities.Exists(x => x.Type == "devices.capabilities.color_setting")
where device.Capabilities.Exists(x => x.Type == "devices.capabilities.range")
where device.Capabilities.Exists(x => x.Type == "devices.capabilities.dynamic_scene")
select device).ToList();
serviceResponse.Success = true;
serviceResponse.Data = devices;
serviceResponse.Message = "Request Successful";
return serviceResponse;
}
/// <inheritdoc/>
public async Task<ServiceResponse<GoveeHttpState>> GetDeviceState(string deviceId, string deviceModel)
{
var serviceResponse = new ServiceResponse<GoveeHttpState>();
var jsonPayload = $@"
{{
""requestId"": ""{Guid.NewGuid()}"",
""payload"": {{
""sku"": ""{deviceModel}"",
""device"": ""{deviceId}""
}}
}}";
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync($"{GoveeApiAddress}{GoveeStateEndpoint}", content);
if (!response.IsSuccessStatusCode)
{
serviceResponse.Success = false;
serviceResponse.Message = response.ReasonPhrase;
return serviceResponse;
}
var state = await response.Content.ReadFromJsonAsync<GoveeHttpState>();
serviceResponse.Success = true;
serviceResponse.Message = "";
serviceResponse.Data = state;
return serviceResponse;
}
/// <inheritdoc/>
public async Task<ServiceResponse<bool>> SetOnOff(string deviceId, string deviceModel, bool on)
{
var serviceResponse = new ServiceResponse<bool>();
var value = "0";
if (on)
{
value = "1";
}
var jsonPayload = $@"
{{
""requestId"": ""{Guid.NewGuid()}"",
""payload"": {{
""sku"": ""{deviceModel}"",
""device"": ""{deviceId}"",
""capability"": {{
""type"": ""devices.capabilities.on_off"",
""instance"": ""powerSwitch"",
""value"": {value}
}}
}}
}}";
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync($"{GoveeApiAddress}{GoveeControlEndpoint}", content);
if (!response.IsSuccessStatusCode)
{
serviceResponse.Success = false;
serviceResponse.Message = response.ReasonPhrase;
return serviceResponse;
}
serviceResponse.Success = true;
serviceResponse.Message = "";
return serviceResponse;
}
/// <inheritdoc/>
public async Task<ServiceResponse<bool>> SetColor(string deviceId, string deviceModel, RgbColor color)
{
var serviceResponse = new ServiceResponse<bool>();
var value = ((color.R & 0xFF) << 16) | ((color.G & 0xFF) << 8) | (color.B & 0xFF);
var jsonPayload = $@"
{{
""requestId"": ""{Guid.NewGuid()}"",
""payload"": {{
""sku"": ""{deviceModel}"",
""device"": ""{deviceId}"",
""capability"": {{
""type"": ""devices.capabilities.color_setting"",
""instance"": ""colorRgb"",
""value"": {value}
}}
}}
}}";
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync($"{GoveeApiAddress}{GoveeControlEndpoint}", content);
if (!response.IsSuccessStatusCode)
{
serviceResponse.Success = false;
serviceResponse.Message = response.ReasonPhrase;
return serviceResponse;
}
serviceResponse.Success = true;
serviceResponse.Message = "";
return serviceResponse;
}
public Task<ServiceResponse<bool>> SetColorTemp(string deviceId, string deviceModel, int value)
{
throw new NotImplementedException();
}
/// <inheritdoc/>
public async Task<ServiceResponse<bool>> SetBrightness(string deviceId, string deviceModel, int value)
{
var serviceResponse = new ServiceResponse<bool>();
var jsonPayload = $@"
{{
""requestId"": ""{Guid.NewGuid()}"",
""payload"": {{
""sku"": ""{deviceModel}"",
""device"": ""{deviceId}"",
""capability"": {{
""type"": ""devices.capabilities.range"",
""instance"": ""brightness"",
""value"": {value}
}}
}}
}}";
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync($"{GoveeApiAddress}{GoveeControlEndpoint}", content);
if (!response.IsSuccessStatusCode)
{
serviceResponse.Success = false;
serviceResponse.Message = response.ReasonPhrase;
return serviceResponse;
}
serviceResponse.Success = true;
serviceResponse.Message = "";
return serviceResponse;
}
/// <inheritdoc/>
public async Task<ServiceResponse<List<GoveeScene>>> GetScenes(string deviceId, string deviceModel)
{
var serviceResponse = new ServiceResponse<List<GoveeScene>>();
var jsonPayload = $@"
{{
""requestId"": ""{Guid.NewGuid()}"",
""payload"": {{
""sku"": ""{deviceModel}"",
""device"": ""{deviceId}""
}}
}}";
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync($"{GoveeApiAddress}{GoveeControlEndpoint}", content);
if (!response.IsSuccessStatusCode)
{
serviceResponse.Success = false;
serviceResponse.Message = response.ReasonPhrase;
return serviceResponse;
}
// TODO Test response Content
serviceResponse.Success = true;
serviceResponse.Message = "";
return serviceResponse;
}
/// <inheritdoc/>
public async Task<ServiceResponse<bool>> SetLightScene(string deviceId, string deviceModel, int sceneValue)
{
var serviceResponse = new ServiceResponse<bool>();
var jsonPayload = $@"
{{
""requestId"": ""{Guid.NewGuid()}"",
""payload"": {{
""sku"": ""{deviceModel}"",
""device"": ""{deviceId}"",
""capability"": {{
""type"": ""devices.capabilities.dynamic_scene"",
""instance"": ""lightScene"",
""value"": {sceneValue}
}}
}}
}}";
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync($"{GoveeApiAddress}{GoveeControlEndpoint}", content);
if (!response.IsSuccessStatusCode)
{
serviceResponse.Success = false;
serviceResponse.Message = response.ReasonPhrase;
return serviceResponse;
}
serviceResponse.Success = true;
serviceResponse.Message = "";
return serviceResponse;
}
/// <inheritdoc/>
public async Task<ServiceResponse<bool>> SetDiyScene(string deviceId, string deviceModel, int sceneValue)
{
var serviceResponse = new ServiceResponse<bool>();
var jsonPayload = $@"
{{
""requestId"": ""{Guid.NewGuid()}"",
""payload"": {{
""sku"": ""{deviceModel}"",
""device"": ""{deviceId}"",
""capability"": {{
""type"": ""devices.capabilities.dynamic_scene"",
""instance"": ""diyScene"",
""value"": {sceneValue}
}}
}}
}}";
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync($"{GoveeApiAddress}{GoveeControlEndpoint}", content);
if (!response.IsSuccessStatusCode)
{
serviceResponse.Success = false;
serviceResponse.Message = response.ReasonPhrase;
return serviceResponse;
}
serviceResponse.Success = true;
serviceResponse.Message = "";
return serviceResponse;
}
}

View File

@ -19,6 +19,7 @@ public class GoveeService : IGoveeService
{ {
if (string.IsNullOrWhiteSpace(GoveeApiKey)) throw new Exception("No Govee Api Key Set!"); if (string.IsNullOrWhiteSpace(GoveeApiKey)) throw new Exception("No Govee Api Key Set!");
_apiService.SetApiKey(GoveeApiKey); _apiService.SetApiKey(GoveeApiKey);
var apiDevices = await _apiService.GetDevices(); var apiDevices = await _apiService.GetDevices();
var devices = apiDevices.Select(apiDevice => new GoveeDevice() { DeviceId = apiDevice.DeviceId, DeviceName = apiDevice.DeviceName, Model = apiDevice.Model, Address = "onlyAvailableOnUdpRequest" }).ToList(); var devices = apiDevices.Select(apiDevice => new GoveeDevice() { DeviceId = apiDevice.DeviceId, DeviceName = apiDevice.DeviceName, Model = apiDevice.Model, Address = "onlyAvailableOnUdpRequest" }).ToList();
if (!onlyLan) if (!onlyLan)
@ -87,6 +88,7 @@ public class GoveeService : IGoveeService
return; return;
} }
if (string.IsNullOrWhiteSpace(GoveeApiKey)) throw new Exception("No Govee Api Key Set!"); if (string.IsNullOrWhiteSpace(GoveeApiKey)) throw new Exception("No Govee Api Key Set!");
_apiService.SetApiKey(GoveeApiKey); _apiService.SetApiKey(GoveeApiKey);
await _apiService.SetColor(goveeDevice.DeviceId, goveeDevice.Model, color); await _apiService.SetColor(goveeDevice.DeviceId, goveeDevice.Model, color);
} }

View File

@ -32,6 +32,8 @@ public class GoveeUdpService : IGoveeUdpService
/// <inheritdoc/> /// <inheritdoc/>
public async Task<List<GoveeUdpDevice>> GetDevices(TimeSpan? timeout = null) public async Task<List<GoveeUdpDevice>> GetDevices(TimeSpan? timeout = null)
{ {
if (!_udpListenerActive)
throw new Exception("Udp Listener not started!");
// Block this Method until current call reaches end of Method // Block this Method until current call reaches end of Method
await _semaphore.WaitAsync(); await _semaphore.WaitAsync();
@ -48,7 +50,7 @@ public class GoveeUdpService : IGoveeUdpService
}; };
// Subscribe to ScanResultSubject // Subscribe to ScanResultSubject
var devicesTask = _scanResultSubject var devicesTask = _scanResultSubject
.TakeUntil(Observable.Timer(timeout ?? TimeSpan.FromMilliseconds(300))) .TakeUntil(Observable.Timer(timeout ?? TimeSpan.FromMilliseconds(250)))
.ToList() .ToList()
.ToTask(); .ToTask();
@ -73,6 +75,8 @@ public class GoveeUdpService : IGoveeUdpService
/// <inheritdoc/> /// <inheritdoc/>
public async Task<GoveeUdpState> GetState(string deviceAddress, int uniCastPort = 4003, TimeSpan? timeout = null) public async Task<GoveeUdpState> GetState(string deviceAddress, int uniCastPort = 4003, TimeSpan? timeout = null)
{ {
if (!_udpListenerActive)
throw new Exception("Udp Listener not started!");
try try
{ {
// Build Message // Build Message
@ -86,7 +90,7 @@ public class GoveeUdpService : IGoveeUdpService
}; };
// Subscribe to ScanResultSubject // Subscribe to ScanResultSubject
var devicesTask = _stateResultSubject var devicesTask = _stateResultSubject
.TakeUntil(Observable.Timer(timeout ?? TimeSpan.FromMilliseconds(200))) .TakeUntil(Observable.Timer(timeout ?? TimeSpan.FromMilliseconds(250)))
.ToTask(); .ToTask();
// Send Message // Send Message
@ -228,6 +232,8 @@ public class GoveeUdpService : IGoveeUdpService
public void StopUdpListener() public void StopUdpListener()
{ {
_udpListenerActive = false; _udpListenerActive = false;
_udpClient.DropMulticastGroup(IPAddress.Parse(GoveeMulticastAddress));
_udpClient.Close();
} }
private static void SendUdpMessage(string message, string receiverAddress, int receiverPort) private static void SendUdpMessage(string message, string receiverAddress, int receiverPort)
@ -249,12 +255,13 @@ public class GoveeUdpService : IGoveeUdpService
} }
} }
private void SetupUdpClientListener() private async void SetupUdpClientListener()
{ {
_udpClient.ExclusiveAddressUse = false; _udpClient.ExclusiveAddressUse = false;
var localEndPoint = new IPEndPoint(IPAddress.Any, GoveeMulticastPortListen); var localEndPoint = new IPEndPoint(IPAddress.Any, GoveeMulticastPortListen);
_udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); _udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
_udpClient.Client.Bind(localEndPoint); _udpClient.Client.Bind(localEndPoint);
await StartListener();
} }
private async Task StartListener() private async Task StartListener()
@ -277,10 +284,9 @@ public class GoveeUdpService : IGoveeUdpService
} }
}); });
} }
finally catch(Exception ex)
{ {
_udpClient.DropMulticastGroup(IPAddress.Parse(GoveeMulticastAddress)); throw ex;
_udpClient.Close();
} }
} }

View File

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\GoveeCSharpConnector\GoveeCSharpConnector.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,299 @@
using System.Net.Mime;
using System.Reflection;
using System.Xml.Linq;
using GoveeCSharpConnector.Objects;
using GoveeCSharpConnector.Services;
namespace GoveeCsharpConnector.Example;
public class Program
{
private static readonly GoveeApiService GoveeApiService = new ();
private static readonly GoveeUdpService GoveeUdpService = new ();
private static List<GoveeApiDevice> _apiDevices = new ();
private static List<GoveeUdpDevice> _udpDevices = new();
public static async Task Main(string[] args)
{
while (true)
{
PrintWelcomeMessage();
var input = Console.ReadLine();
HandleKeyInput(input);
}
}
private static async void HandleKeyInput(string input)
{
switch (input)
{
case "1":
HandleApiInput();
EndSegment();
break;
case "2":
Console.WriteLine("Requesting Devices ...");
_apiDevices = await GoveeApiService.GetDevices();
Console.WriteLine("Devices:");
foreach (var device in _apiDevices)
{
Console.WriteLine($"Name: {device.DeviceName}, Device Id: {device.DeviceId}, Model: {device.Model}, Controllable {device.Controllable}");
}
Console.WriteLine($"Total: {_apiDevices.Count} Devices.");
EndSegment();
break;
case "3":
if (_apiDevices.Count == 0)
{
Console.WriteLine("No Devices discovered! Please use Option 2 first!");
EndSegment();
return;
}
Console.WriteLine("Please enter the Name of the Device:");
var nameInput = Console.ReadLine()?.ToLower();
if (string.IsNullOrWhiteSpace(nameInput) || _apiDevices.FirstOrDefault(x => x.DeviceName.ToLower() == nameInput) is null)
{
Console.WriteLine("Device Name Invalid!");
EndSegment();
return;
}
Console.WriteLine($"Do you want to turn the Device {nameInput} on or off?");
var onOffInput = Console.ReadLine()?.ToLower();
if (string.IsNullOrWhiteSpace(onOffInput) || (onOffInput != "on" && onOffInput != "off"))
{
Console.WriteLine("Invalid Input!");
EndSegment();
return;
}
if (input == "on")
{
await GoveeApiService.ToggleState(_apiDevices.First(x => x.DeviceName.ToLower() == nameInput).DeviceId, _apiDevices.First(x => x.DeviceName.ToLower() == nameInput).Model, true);
}
else
{
await GoveeApiService.ToggleState(_apiDevices.First(x => x.DeviceName.ToLower() == nameInput).DeviceId, _apiDevices.First(x => x.DeviceName.ToLower() == nameInput).Model, false);
}
EndSegment();
break;
case "4":
if (_apiDevices.Count == 0)
{
Console.WriteLine("No Devices discovered! Please use Option 2 first!");
EndSegment();
return;
}
Console.WriteLine("Please enter the Name of the Device:");
var nameInput2 = Console.ReadLine()?.ToLower();
if (string.IsNullOrWhiteSpace(nameInput2) || _apiDevices.FirstOrDefault(x => x.DeviceName.ToLower() == nameInput2) is null)
{
Console.WriteLine("Device Name Invalid!");
EndSegment();
return;
}
Console.WriteLine($"Please enter a Brightness Value for Device {nameInput2}. 0-100");
var brightnessInput = Console.ReadLine();
int value = Convert.ToInt16(brightnessInput);
if (string.IsNullOrWhiteSpace(brightnessInput) || value < 0 || value > 100)
{
Console.WriteLine("Invalid Input!");
EndSegment();
return;
}
await GoveeApiService.SetBrightness(_apiDevices.First(x => x.DeviceName.ToLower() == nameInput2).DeviceId, _apiDevices.First(x => x.DeviceName.ToLower() == nameInput2).Model, value);
Console.WriteLine($"Set Brightness of Device {nameInput2} to {value}%!");
EndSegment();
break;
case "5":
if (_apiDevices.Count == 0)
{
Console.WriteLine("No Devices discovered! Please use Option 2 first!");
EndSegment();
return;
}
Console.WriteLine("Please enter the Name of the Device:");
var nameInput3 = Console.ReadLine()?.ToLower();
if (string.IsNullOrWhiteSpace(nameInput3) || _apiDevices.FirstOrDefault(x => x.DeviceName.ToLower() == nameInput3) is null)
{
Console.WriteLine("Device Name Invalid!");
EndSegment();
return;
}
Console.WriteLine($"Please choose a Color to set {nameInput3} to ... (blue, red, green)");
var colorInput = Console.ReadLine()?.ToLower();
if (string.IsNullOrWhiteSpace(colorInput) || (colorInput != "blue" && colorInput != "green" && colorInput != "red"))
{
Console.WriteLine("Invalid Input!");
EndSegment();
return;
}
var model = _apiDevices.FirstOrDefault(x => x.DeviceName.ToLower()== nameInput3)?.Model;
switch (colorInput)
{
case "blue":
await GoveeApiService.SetColor(_apiDevices.First(x => x.DeviceName.ToLower() == nameInput3).DeviceId, model, new RgbColor(0, 0 ,254));
break;
case "green":
await GoveeApiService.SetColor(_apiDevices.First(x => x.DeviceName.ToLower() == nameInput3).DeviceId, model, new RgbColor(0, 254 ,0));
break;
case "red":
await GoveeApiService.SetColor(_apiDevices.First(x => x.DeviceName.ToLower() == nameInput3).DeviceId, model, new RgbColor(254, 0 ,0));
break;
}
Console.WriteLine($"Set Color of Device {nameInput3} to {colorInput}!");
EndSegment();
break;
case "6":
Console.WriteLine("Requesting Devices ...");
_udpDevices = await GoveeUdpService.GetDevices();
Console.WriteLine("Devices:");
foreach (var device in _udpDevices)
{
Console.WriteLine($"IpAddress: {device.ip}, Device Id: {device.device}, Model: {device.sku}");
}
Console.WriteLine($"Total: {_udpDevices.Count} Devices.");
EndSegment();
break;
case "7":
var selectedDevice = GetUdpDeviceSelection();
Console.WriteLine($"Do you want to turn the Device {selectedDevice.ip} on or off?");
var onOffInput2 = Console.ReadLine()?.ToLower();
if (string.IsNullOrWhiteSpace(onOffInput2) || (onOffInput2 != "on" && onOffInput2 != "off"))
{
Console.WriteLine("Invalid Input!");
EndSegment();
return;
}
if (input == "on")
{
await GoveeUdpService.ToggleDevice(selectedDevice.ip, true);
}
else
{
await GoveeUdpService.ToggleDevice(selectedDevice.ip, false);
}
EndSegment();
break;
case "8":
var selectedDevice2 = GetUdpDeviceSelection();
Console.WriteLine($"Please enter a Brightness Value for Device {selectedDevice2.ip}. 0-100");
var brightnessInput2 = Console.ReadLine();
int value2 = Convert.ToInt16(brightnessInput2);
if (string.IsNullOrWhiteSpace(brightnessInput2) || value2 < 0 || value2 > 100)
{
Console.WriteLine("Invalid Input!");
EndSegment();
return;
}
await GoveeUdpService.SetBrightness(selectedDevice2.ip, value2);
Console.WriteLine($"Set Brightness of Device {selectedDevice2.ip} to {value2}%!");
EndSegment();
break;
case "9":
var selectedDevice3 = GetUdpDeviceSelection();
Console.WriteLine($"Please choose a Color to set {selectedDevice3.ip} to ... (blue, red, green)");
var colorInput2 = Console.ReadLine()?.ToLower();
if (string.IsNullOrWhiteSpace(colorInput2) || (colorInput2 != "blue" && colorInput2 != "green" && colorInput2 != "red"))
{
Console.WriteLine("Invalid Input!");
EndSegment();
return;
}
switch (colorInput2)
{
case "blue":
GoveeUdpService.SetColor(selectedDevice3.ip, new RgbColor(0, 0, 254));
break;
case "green":
GoveeUdpService.SetColor(selectedDevice3.ip, new RgbColor(0, 254, 0));
break;
case "red":
GoveeUdpService.SetColor(selectedDevice3.ip, new RgbColor(254, 0, 0));
break;
}
Console.WriteLine($"Set Color of Device {selectedDevice3.ip} to {colorInput2}!");
EndSegment();
break;
}
}
private static GoveeUdpDevice GetUdpDeviceSelection()
{
var count = 1;
Console.WriteLine("Please Choose a Device from the List:");
foreach (var device in _udpDevices)
{
Console.WriteLine($"{count} - IpAdress: {device.ip}, Device Id {device.device}, Model {device.sku}");
count++;
}
var input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input) || Int16.TryParse(input, out var result) is false)
{
Console.WriteLine("Invalid Input!");
return GetUdpDeviceSelection();
}
return _udpDevices[result-1];
}
private static void HandleApiInput()
{
while (true)
{
Console.WriteLine("Please enter/paste your Govee Api Key ...");
Console.WriteLine("Your Api Key should look something like this: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx");
var input = Console.ReadLine();
if (input is null || input.Length != 36)
{
Console.WriteLine("Wrong Api Key Format!");
continue;
}
GoveeApiService.SetApiKey(input);
break;
}
Console.WriteLine("Api Key saved!");
}
private static void EndSegment()
{
Console.WriteLine("---------------------------Press any Key to continue---------------------------");
Console.ReadLine();
}
private static void PrintWelcomeMessage()
{
Console.WriteLine();
Console.WriteLine("Welcome to the GoveeCSharpConnector Example!");
Console.WriteLine($"Version: {Assembly.GetEntryAssembly()?.GetName().Version}");
Console.WriteLine($"To test/explore the GoveeCSharpConnector Version: {Assembly.Load("GoveeCSharpConnector").GetName().Version}");
Console.WriteLine("----------------------------------------------------------");
if (string.IsNullOrEmpty(GoveeApiService.GetApiKey()))
{
Console.WriteLine("1 - Enter GoveeApi Key - START HERE (Required for Api Service Options!)");
}
else
{
Console.WriteLine("1 - Enter GoveeApi Key - Already Set!");
Console.WriteLine("Api Service:");
Console.WriteLine("2 - Get a List of all Devices connected to the Api Key Account");
Console.WriteLine("3 - Turn Device On or Off");
Console.WriteLine("4 - Set Brightness for Device");
Console.WriteLine("5 - Set Color of Device");
}
Console.WriteLine("Udp Service - No Api Key needed!");
Console.WriteLine("6 - Get a List of all Devices available in the Network");
Console.WriteLine("7 - Turn Device On or Off");
Console.WriteLine("8 - Set Brightness for Device");
Console.WriteLine("9 - Set Color of Device");
}
}

View File

@ -1,7 +1,8 @@
# GoveeCSharpConnector # GoveeCSharpConnector
![netStandard2.0](https://img.shields.io/badge/.NET%20Standard-2.0-blueviolet) ![netStandard2.0](https://img.shields.io/badge/.NET%20Standard-2.0-blueviolet)
[![Nuget](https://img.shields.io/nuget/v/GoveeApiClient?cacheSeconds=50)](https://www.nuget.org/packages/GoveeCSharpConnector/) [![Nuget](https://img.shields.io/nuget/v/GoveeCSharpConnector?cacheSeconds=50)](https://www.nuget.org/packages/GoveeCSharpConnector/)
# About # About
Simple .net Library to interface with Govee Smart Lights via their Web Api or Lan Udp connection. Simple .net Library to interface with Govee Smart Lights via their Web Api or Lan Udp connection.