16 Commits
main ... dev

Author SHA1 Message Date
3c19797f72 Added Get Scenes Method 2024-02-26 05:32:07 +01:00
fdf74f5f52 Added Set Scenes Methods
Changed Control Endpoints
2024-02-26 05:23:59 +01:00
20a9b726a4 Added New Guids to Requests 2024-02-26 04:59:04 +01:00
da62e176cd Delete old Files 2024-02-26 04:49:33 +01:00
368de74820 Removed Example Console Project
Removed Old Api Classes
Added new Http Api Service and Classes
TODO Dynamic Effect Methods
2024-02-26 04:47:47 +01:00
8cb2a51cd3 Marking "old" Api as Obsoloete 2024-02-11 05:08:29 +01:00
d2cd0f0fe0 changed workflow added readme 2024-02-08 14:26:55 +01:00
1a69dad891 Set Api Key on Request 2024-02-03 01:24:00 +01:00
488211e307 Update GoveeCSharpConnector.csproj 2024-02-03 00:56:00 +01:00
d24b3592ac Moved Class and changed Namespace 2024-02-03 00:52:45 +01:00
1b099f2a5e Added ApiKey check 2024-02-03 00:51:28 +01:00
b8c838caa3 Added UdpListener check 2024-02-03 00:49:18 +01:00
ecfcd26b47 Added GoveeService that unites Api and Udp Service
Added ColorTemp Method to Udp Service
2024-02-03 00:48:12 +01:00
4b537633f6 Added Readme, Added Nuget Infos in Project 2024-02-02 19:05:25 +01:00
15a7332931 Merge branch 'main' into dev 2024-02-02 18:52:16 +01:00
2b0aefba60 Delete .gitignore 2024-02-02 18:47:02 +01:00
37 changed files with 894 additions and 521 deletions

106
.github/workflows/nuget.yml vendored Normal file
View File

@ -0,0 +1,106 @@
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
name: publish
on:
workflow_dispatch: # Allow running the workflow manually from the GitHub UI
push:
branches:
- 'main' # Run the workflow when pushing to the main branch
pull_request:
branches:
- '*' # Run the workflow for all pull requests
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:
create_nuget:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Get all history to allow automatic versioning using MinVer
# Install the .NET SDK indicated in the global.json file
- name: Setup .NET
uses: actions/setup-dotnet@v4
# Create the NuGet package in the folder from the environment variable NuGetDirectory
- run: dotnet pack --configuration Release --output ${{ env.NuGetDirectory }}
# Publish the NuGet package as an artifact, so they can be used in the following jobs
- 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

@ -1,13 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Rider ignored files
/contentModel.xml
/projectSettingsUpdater.xml
/.idea.GoveeCSharpConnector.iml
/modules.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

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

View File

@ -1,2 +1,3 @@
<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></wpf:ResourceDictionary>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Govee/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=reauired/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@ -5,16 +5,22 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>disable</Nullable>
<LangVersion>latest</LangVersion>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Title>CSharp Library to control Govee Lights via Govee Web Api and Lan Udp!</Title>
<Authors>Locxion</Authors>
<Description>CSharp Library to control Govee Lights via Govee Web Api and Lan Udp!</Description>
<PackageProjectUrl>https://github.com/Locxion/GoveeCSharpConnector</PackageProjectUrl>
<RepositoryUrl>https://github.com/Locxion/GoveeCSharpConnector</RepositoryUrl>
<PackageLicenseUrl>https://github.com/Locxion/GoveeCSharpConnector/blob/main/LICENSE</PackageLicenseUrl>
<Version>1.1.2</Version>
<PackageReadmeFile>../README.md</PackageReadmeFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Net.Http.Json" Version="8.0.0" />
<PackageReference Include="System.Reactive" Version="6.0.0" />
<PackageReference Include="System.Text.Json" Version="8.0.1" />
</ItemGroup>
<ItemGroup>
<Folder Include="Properties\" />
</ItemGroup>
</Project>

View File

@ -1,8 +1,9 @@
using GoveeCSharpConnector.Objects;
using GoveeCSharpConnector.Objects.Misc;
namespace GoveeCSharpConnector.Interfaces;
public interface IGoveeApiService
public interface IGoveeHttpService
{
/// <summary>
/// Sets the required Api Key for the Govee Api.
@ -22,15 +23,15 @@ public interface IGoveeApiService
/// <summary>
/// Requests all Devices registered to Api Key Govee Account
/// </summary>
/// <returns>List of GoveeApiDevices</returns>
Task<List<GoveeApiDevice>> GetDevices();
/// <returns>List of GoveeHttpDevices</returns>
Task<ServiceResponse<List<GoveeHttpDevice>>> GetDevices();
/// <summary>
/// Requests the State of a single Govee Device
/// </summary>
/// <param name="deviceId">Device Id Guid as string</param>
/// <param name="deviceModel">Device Model Number as string</param>
/// <returns>GoveeApiStat Object</returns>
public Task<GoveeApiState> GetDeviceState(string deviceId, string deviceModel);
/// <returns>GoveeHttpState Object</returns>
Task<ServiceResponse<GoveeHttpState>> GetDeviceState(string deviceId, string deviceModel);
/// <summary>
/// Sets the On/Off state of a single Govee Device
/// </summary>
@ -38,15 +39,7 @@ public interface IGoveeApiService
/// <param name="deviceModel">Device Model Number as string</param>
/// <param name="on"></param>
/// <returns></returns>
public 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>
public Task SetBrightness(string deviceId, string deviceModel, int value);
Task<ServiceResponse<bool>> SetOnOff(string deviceId, string deviceModel, bool on);
/// <summary>
/// Sets a Rgb Color of a single Govee Device
/// </summary>
@ -54,7 +47,7 @@ public interface IGoveeApiService
/// <param name="deviceModel">Device Model Number as string</param>
/// <param name="color">Rgb Color</param>
/// <returns></returns>
public Task SetColor(string deviceId, string deviceModel, RgbColor color);
Task<ServiceResponse<bool>> SetColor(string deviceId, string deviceModel, RgbColor color);
/// <summary>
/// Sets the Color Temperature of a single Govee Device
/// </summary>
@ -62,6 +55,37 @@ public interface IGoveeApiService
/// <param name="deviceModel">Device Model Number as string</param>
/// <param name="value">Color Temp in Kelvin as Int</param>
/// <returns></returns>
public Task SetColorTemp(string deviceId, string deviceModel, int value);
Task<ServiceResponse<bool>> 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

@ -0,0 +1,62 @@
using GoveeCSharpConnector.Objects;
namespace GoveeCSharpConnector.Interfaces;
public interface IGoveeService
{
/// <summary>
/// Govee Api Key
/// </summary>
string GoveeApiKey { get; set; }
/// <summary>
/// Gets a List of Govee Devices
/// </summary>
/// <param name="onlyLan">If true returns that are available on Api and Lan</param>
/// <returns>List of Govee Devices</returns>
Task<List<GoveeDevice>> GetDevices(bool onlyLan = true);
/// <summary>
/// Gets the State of a GoveeDevice
/// </summary>
/// <param name="goveeDevice">GoveeDevice</param>
/// <param name="useUdp">Use Udp Connection instead of the Api</param>
/// <returns></returns>
Task<GoveeState> GetDeviceState(GoveeDevice goveeDevice, bool useUdp = true);
/// <summary>
/// Sets the On/Off State of the GoveeDevice
/// </summary>
/// <param name="goveeDevice">GoveeDevice</param>
/// <param name="on"></param>
/// <param name="useUdp">Use Udp Connection instead of the Api</param>
/// <returns></returns>
Task ToggleState(GoveeDevice goveeDevice, bool on, bool useUdp = true);
/// <summary>
/// Sets the Brightness of the GoveeDevice
/// </summary>
/// <param name="goveeDevice">GoveeDevice</param>
/// <param name="value">Brightness in Percent</param>
/// <param name="useUdp">Use Udp Connection instead of the Api</param>
/// <returns></returns>
Task SetBrightness(GoveeDevice goveeDevice, int value, bool useUdp = true);
/// <summary>
/// Sets the Color of the GoveeDevice
/// </summary>
/// <param name="goveeDevice">GoveeDevice</param>
/// <param name="color">RgBColor</param>
/// <param name="useUdp">Use Udp Connection instead of the Api</param>
/// <returns></returns>
Task SetColor(GoveeDevice goveeDevice, RgbColor color, bool useUdp = true);
/// <summary>
/// Sets the Color Temperature in Kelvin for the GoveeDevice
/// </summary>
/// <param name="goveeDevice">GoveeDevice</param>
/// <param name="value">Color Temp in Kelvin</param>
/// <param name="useUdp">Use Udp Connection instead of the Api</param>
/// <returns></returns>
Task SetColorTemp(GoveeDevice goveeDevice, int value, bool useUdp = true);
}

View File

@ -49,6 +49,15 @@ public interface IGoveeUdpService
/// <param name="uniCastPort">Port of the Device. Standard 4003</param>
/// <returns></returns>
Task SetColor(string deviceAddress, RgbColor color, int uniCastPort = 4003);
/// <summary>
/// Sets the ColorTemp of the Device
/// </summary>
/// <param name="deviceAddress">Ip Address of the Device</param>
/// <param name="colorTempInKelvin"></param>
/// <param name="uniCastPort">Port of the Device. Standard 4003</param>
/// <returns></returns>
Task SetColorTemp(string deviceAddress, int colorTempInKelvin, int uniCastPort = 4003);
/// <summary>
/// Starts the Udp Listener
/// </summary>

View File

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

View File

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

View File

@ -1,14 +0,0 @@
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

@ -1,17 +0,0 @@
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

@ -1,16 +0,0 @@
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

@ -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; }
}

View File

@ -0,0 +1,14 @@
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

@ -0,0 +1,16 @@
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

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

View File

@ -0,0 +1,13 @@
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

@ -2,11 +2,10 @@ using GoveeCSharpConnector.Enums;
namespace GoveeCSharpConnector.Objects;
public class Properties
public class GoveeState
{
public bool Online { get; set; }
public PowerState PowerState { get; set; }
public PowerState State { get; set; }
public int Brightness { get; set; }
public int? ColorTemp { get; set; }
public RgbColor Color { get; set; }
public int ColorTempInKelvin { get; set; }
}

View File

@ -0,0 +1,13 @@
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

@ -0,0 +1,13 @@
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

@ -0,0 +1,21 @@
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

@ -0,0 +1,11 @@
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

@ -0,0 +1,17 @@
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

@ -0,0 +1,13 @@
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

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

View File

@ -0,0 +1,13 @@
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

@ -0,0 +1,12 @@
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

@ -0,0 +1,8 @@
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

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

View File

@ -1,85 +0,0 @@
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

@ -0,0 +1,306 @@
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

@ -0,0 +1,106 @@
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<List<GoveeDevice>> GetDevices(bool onlyLan = true)
{
if (string.IsNullOrWhiteSpace(GoveeApiKey)) throw new Exception("No Govee Api Key Set!");
_apiService.SetApiKey(GoveeApiKey);
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<GoveeState> 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!");
_apiService.SetApiKey(GoveeApiKey);
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!");
_apiService.SetApiKey(GoveeApiKey);
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!");
_apiService.SetApiKey(GoveeApiKey);
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!");
_apiService.SetApiKey(GoveeApiKey);
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!");
_apiService.SetApiKey(GoveeApiKey);
await _apiService.SetColorTemp(goveeDevice.DeviceId, goveeDevice.Model, value);
}
}

View File

@ -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;
}
}
/// <inheritdoc/>
public async void StartUdpListener()
{

View File

@ -1,14 +0,0 @@
<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

@ -1,299 +0,0 @@
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];
}
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");
}
}

7
README.md Normal file
View File

@ -0,0 +1,7 @@
# GoveeCSharpConnector
![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/)
# About
Simple .net Library to interface with Govee Smart Lights via their Web Api or Lan Udp connection.