HAcontrol/MainWindow.axaml.cs
2025-08-16 20:11:06 +02:00

293 lines
No EOL
12 KiB
C#

using System;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
namespace HAcontrol;
public partial class MainWindow : Window
{
private Settings? settings = null;
private System.Threading.CancellationTokenSource? _cts;
private static MainWindow? self;
public static MainWindow? Self => self;
public bool ShowFader => !string.IsNullOrEmpty(settings?.FaderEntity);
private PixelPoint? _windowPosition;
public MainWindow()
{
self = this;
InitializeComponent();
Topmost = true;
LoadSettings();
// Restore window position if available
if (settings != null)
{
if (settings.WindowTop != 0 || settings.WindowLeft != 0)
this.Position = new Avalonia.PixelPoint((int)settings.WindowLeft, (int)settings.WindowTop);
}
_cts = new System.Threading.CancellationTokenSource();
StartStatePolling(_cts.Token);
}
public void LoadSettings()
{
if (!File.Exists(SettingsWindow.SettingsFile))
{
// Create default settings file if it does not exist
var defaultSettings = new Settings();
var json = JsonSerializer.Serialize(defaultSettings, new JsonSerializerOptions { WriteIndented = true });
File.WriteAllText(SettingsWindow.SettingsFile, json);
}
{
var json = File.ReadAllText(SettingsWindow.SettingsFile);
settings = JsonSerializer.Deserialize<Settings>(json);
}
FaderControl.IsVisible = ShowFader;
var newHeight = ShowFader ? 500 : 100;
MaxHeight = newHeight;
MinHeight = newHeight;
Height = newHeight;
}
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
// Save window position
if (settings != null && _windowPosition != null)
{
settings.WindowTop = _windowPosition.Value.Y;
settings.WindowLeft = _windowPosition.Value.X;
var json = System.Text.Json.JsonSerializer.Serialize(settings, new System.Text.Json.JsonSerializerOptions { WriteIndented = true });
System.IO.File.WriteAllText(SettingsWindow.SettingsFile, json);
}
_cts?.Cancel();
_cts?.Dispose();
self = null;
}
private async void StartStatePolling(System.Threading.CancellationToken token)
{
while (!token.IsCancellationRequested)
{
await GetState();
try
{
await Task.Delay(10000, token);
}
catch (TaskCanceledException)
{
break;
}
}
}
private async void Button_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
if (settings == null || string.IsNullOrEmpty(settings.HomeAssistantUrl) || string.IsNullOrEmpty(settings.WebhookId))
{
StatusText.Content = "Einstellungen fehlen!";
StatusText.Foreground = new Avalonia.Media.SolidColorBrush(Avalonia.Media.Colors.Red);
return;
}
string webhookUrl = $"{settings.HomeAssistantUrl}/api/webhook/{settings.WebhookId}";
string payload = "{\"event\": \"\"}";
// HttpClientHandler to ignore SSL certificate errors (for development only!)
var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true;
using (var client = new HttpClient(handler))
{
var content = new StringContent(payload, Encoding.UTF8, "application/json");
using var _ = await client.PostAsync(webhookUrl, content);
await Task.Delay(100);
}
await GetState();
}
private async Task GetState()
{
_windowPosition = Position;
if (settings == null || string.IsNullOrEmpty(settings.HomeAssistantUrl) || string.IsNullOrEmpty(settings.Entity) || string.IsNullOrEmpty(settings.AccessToken))
{
StatusText.Content = "Einstellungen fehlen!";
StatusText.Foreground = new Avalonia.Media.SolidColorBrush(Avalonia.Media.Colors.Red);
return;
}
try
{
// HttpClientHandler to ignore SSL certificate errors (for development only!)
var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true;
using (var client = new HttpClient(handler))
{
string statusUrl = $"{settings.HomeAssistantUrl}/api/states/{settings.Entity}";
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", settings.AccessToken);
using (var response = await client.GetAsync(statusUrl))
{
string statusJson = await response.Content.ReadAsStringAsync();
// Parse the JSON and extract the state
try
{
var jsonDoc = JsonDocument.Parse(statusJson);
string? state = jsonDoc.RootElement.GetProperty("state").GetString();
string? entity = jsonDoc.RootElement.GetProperty("entity_id").GetString();
StatusText.Content = $"{state}";
if (state == "on")
StatusText.Foreground = new Avalonia.Media.SolidColorBrush(Avalonia.Media.Colors.Green);
else if (state == "off")
StatusText.Foreground = new Avalonia.Media.SolidColorBrush(Avalonia.Media.Colors.Red);
else
StatusText.Foreground = new Avalonia.Media.SolidColorBrush(Avalonia.Media.Colors.Orange);
}
catch
{
StatusText.Content = "Fehler!";
StatusText.Foreground = new Avalonia.Media.SolidColorBrush(Avalonia.Media.Colors.Red);
}
}
if (!string.IsNullOrEmpty(settings.FaderEntity))
{
statusUrl = $"{settings.HomeAssistantUrl}/api/states/{settings.FaderEntity}";
using (var response = await client.GetAsync(statusUrl))
{
string statusJson = await response.Content.ReadAsStringAsync();
// Parse the JSON and extract the state
try
{
// {"entity_id":"number.wing_pp_control_main_4_fader","state":"20.0000002980232","attributes":{"min":0,"max":100,"step":1.0,"mode":"auto","db":"-38.0","low_precision":20.0,"attribution":"","icon":"mdi:volume-source","friendly_name":"Main 4 Fader"},"last_changed":"2025-08-16T14:14:32.455801+00:00","last_reported":"2025-08-16T14:14:32.455801+00:00","last_updated":"2025-08-16T14:14:32.455801+00:00","context":{"id":"01K2SKPTR48X14WGRN6AZDP4Y4","parent_id":null,"user_id":"d548e3619c124b8ead8043c4d6e9223b"}}
var jsonDoc = JsonDocument.Parse(statusJson);
string? state = jsonDoc.RootElement.GetProperty("state").GetString();
string? entity = jsonDoc.RootElement.GetProperty("entity_id").GetString();
if (double.TryParse(state, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out double faderValue))
{
FaderControl.Value = faderValue;
FaderControl.IsVisible = true;
}
else
{
FaderControl.Value = 0.0;
FaderControl.IsVisible = false;
}
}
catch
{
FaderControl.Value = 0.0;
FaderControl.IsVisible = false;
}
}
}
}
}
catch (Exception ex)
{
StatusText.Content = "Fehler!";
StatusText.Foreground = new Avalonia.Media.SolidColorBrush(Avalonia.Media.Colors.Red);
Console.WriteLine($"Error fetching state: {ex.Message}");
}
}
private void SettingsButton_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
var settingsWindow = new SettingsWindow();
settingsWindow.ShowDialog(this);
}
private async void Fader_ValueChanged(object? sender, RangeBaseValueChangedEventArgs e)
{
if (settings == null || string.IsNullOrEmpty(settings.HomeAssistantUrl) || string.IsNullOrEmpty(settings.FaderEntity))
{
StatusText.Content = "Einstellungen fehlen!";
StatusText.Foreground = new Avalonia.Media.SolidColorBrush(Avalonia.Media.Colors.Red);
return;
}
string newState = e.NewValue.ToString(System.Globalization.CultureInfo.InvariantCulture);
await ChangeEntityState(settings.FaderEntity, newState);
}
private async Task ChangeEntityState(string entity, string newState)
{
if (settings == null || string.IsNullOrEmpty(settings.HomeAssistantUrl) || string.IsNullOrEmpty(settings.AccessToken))
{
Console.WriteLine("Einstellungen fehlen!");
return;
}
var url = $"{settings.HomeAssistantUrl}/api/states/{entity}";
var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true;
using var client = new HttpClient(handler);
// Setze den Authorization-Header
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", settings.AccessToken);
// Erstelle den JSON-Inhalt
var jsonContent = new
{
state = newState
};
var content = new StringContent(JsonSerializer.Serialize(jsonContent), Encoding.UTF8, "application/json");
try
{
// Sende die POST-Anfrage
HttpResponseMessage response = await client.PostAsync(url, content);
// Überprüfe den Statuscode der Antwort
if (response.IsSuccessStatusCode)
{
Console.WriteLine("Status erfolgreich geändert.");
}
else
{
Console.WriteLine($"Fehler: {response.StatusCode} - {await response.Content.ReadAsStringAsync()}");
}
}
catch (Exception ex)
{
Console.WriteLine($"Ein Fehler ist aufgetreten: {ex.Message}");
}
}
private void FaderControl_PointerWheelChanged(object? sender, Avalonia.Input.PointerWheelEventArgs e)
{
if (FaderControl.IsVisible && FaderControl.IsEnabled)
{
double delta = e.Delta.Y > 0 ? 0.5 : -0.5;
double newValue = FaderControl.Value + delta;
if (newValue < FaderControl.Minimum) newValue = FaderControl.Minimum;
if (newValue > FaderControl.Maximum) newValue = FaderControl.Maximum;
FaderControl.Value = newValue;
}
}
}