From 93072d4dcdb3f4acec1f6116ab33e9c23020eca4 Mon Sep 17 00:00:00 2001 From: sleevezipper Date: Fri, 8 Jan 2021 01:41:43 +0100 Subject: [PATCH] wip notify infrastructure --- .../Communication/MQTT/MqttPublisher.cs | 46 ++++++++++++-- .../Domain/Notify/Notifier.cs | 60 +++++++++++++++++++ hass-workstation-service/Program.cs | 2 + hass-workstation-service/Worker.cs | 1 + .../hass-workstation-service.csproj | 1 + 5 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 hass-workstation-service/Domain/Notify/Notifier.cs diff --git a/hass-workstation-service/Communication/MQTT/MqttPublisher.cs b/hass-workstation-service/Communication/MQTT/MqttPublisher.cs index c9f0bc8..1623c9e 100644 --- a/hass-workstation-service/Communication/MQTT/MqttPublisher.cs +++ b/hass-workstation-service/Communication/MQTT/MqttPublisher.cs @@ -1,16 +1,19 @@ using System; +using System.Text; using System.Text.Json; using System.Threading; using System.Threading.Tasks; using hass_workstation_service.Communication.InterProcesCommunication.Models; using hass_workstation_service.Communication.Util; using hass_workstation_service.Data; +using hass_workstation_service.Domain.Notify; using Microsoft.Extensions.Logging; using MQTTnet; using MQTTnet.Adapter; using MQTTnet.Client; using MQTTnet.Client.Options; using Serilog; +using static hass_workstation_service.Domain.Notify.Notifier; namespace hass_workstation_service.Communication { @@ -20,6 +23,7 @@ namespace hass_workstation_service.Communication private readonly IMqttClient _mqttClient; private readonly ILogger _logger; private readonly IConfigurationService _configurationService; + private readonly Notifier _notifier; private string _mqttClientMessage { get; set; } public DateTime LastConfigAnnounce { get; private set; } public DeviceConfigModel DeviceConfigModel { get; private set; } @@ -41,12 +45,14 @@ namespace hass_workstation_service.Communication public MqttPublisher( ILogger logger, DeviceConfigModel deviceConfigModel, - IConfigurationService configurationService) + IConfigurationService configurationService, + Notifier notifier) { this._logger = logger; this.DeviceConfigModel = deviceConfigModel; this._configurationService = configurationService; + this._notifier = notifier; var options = _configurationService.GetMqttClientOptionsAsync().Result; _configurationService.MqqtConfigChangedHandler = this.ReplaceMqttClient; @@ -63,11 +69,20 @@ namespace hass_workstation_service.Communication { this._mqttClientMessage = "Not configured"; } - - this._mqttClient.UseConnectedHandler(e => { + + this._mqttClient.UseConnectedHandler(e => + { this._mqttClientMessage = "All good"; + + // subscribe to the default notify topic + this._mqttClient.SubscribeAsync( + new MqttTopicFilterBuilder() + .WithTopic($"homeassistant/sensor/{this.DeviceConfigModel.Name}/notify") + .Build()); }); + this._mqttClient.UseApplicationMessageReceivedHandler(e => this.HandleMessageReceived(e.ApplicationMessage)); + // configure what happens on disconnect this._mqttClient.UseDisconnectedHandler(async e => { @@ -135,12 +150,35 @@ namespace hass_workstation_service.Communication this._mqttClientMessage = ex.ResultCode.ToString(); Log.Logger.Error("Could not connect to broker: " + ex.ResultCode.ToString()); } - + } public MqqtClientStatus GetStatus() { return new MqqtClientStatus() { IsConnected = _mqttClient.IsConnected, Message = _mqttClientMessage }; } + + private void HandleMessageReceived(MqttApplicationMessage applicationMessage) + { + NotificationModel notification; + try + { + notification = JsonSerializer.Deserialize(Encoding.UTF8.GetString(applicationMessage?.Payload)); + } + catch (Exception) + { + notification = new NotificationModel("Error", $"Invalid message: {Encoding.UTF8.GetString(applicationMessage?.Payload)}"); + } + + + this._notifier.GenerateToast(notification); + Console.WriteLine("### RECEIVED APPLICATION MESSAGE ###"); + Console.WriteLine($"+ Topic = {applicationMessage.Topic}"); + + Console.WriteLine($"+ Payload = {Encoding.UTF8.GetString(applicationMessage?.Payload)}"); + Console.WriteLine($"+ QoS = {applicationMessage.QualityOfServiceLevel}"); + Console.WriteLine($"+ Retain = {applicationMessage.Retain}"); + Console.WriteLine(); + } } } diff --git a/hass-workstation-service/Domain/Notify/Notifier.cs b/hass-workstation-service/Domain/Notify/Notifier.cs new file mode 100644 index 0000000..4c198ad --- /dev/null +++ b/hass-workstation-service/Domain/Notify/Notifier.cs @@ -0,0 +1,60 @@ +using Serilog; +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; +using System.Text.Json.Serialization; +using Windows.Data.Xml.Dom; +using Windows.UI.Notifications; + +namespace hass_workstation_service.Domain.Notify +{ + public class Notifier + { + public void GenerateToast(NotificationModel notificationModel) + { + var template = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastImageAndText04); + + var textNodes = template.GetElementsByTagName("text"); + + textNodes[0].AppendChild(template.CreateTextNode(notificationModel.Title)); + textNodes[2].AppendChild(template.CreateTextNode(notificationModel.Content)); + + if (File.Exists(notificationModel.ImagePath)) + { + XmlNodeList toastImageElements = template.GetElementsByTagName("image"); + ((XmlElement)toastImageElements[0]).SetAttribute("src", notificationModel.ImagePath); + } + IXmlNode toastNode = template.SelectSingleNode("/toast"); + ((XmlElement)toastNode).SetAttribute("duration", "long"); + + var notifier = ToastNotificationManager.CreateToastNotifier("Home Assistant"); + var notification = new ToastNotification(template); + + notifier.Show(notification); + } + + public class NotificationModel + { + public string Title { get; private set; } + public string Content { get; private set; } + public string ImagePath { get; private set; } + + [JsonConstructor] + public NotificationModel(string title, string content) + { + Title = title; + Content = content; + this.ImagePath = Path.Combine(Environment.CurrentDirectory, @"hass-workstation-logo.ico"); + } + + public NotificationModel(string title, string content, string imagePath) + { + Title = title; + Content = content; + ImagePath = imagePath; + } + } + } +} diff --git a/hass-workstation-service/Program.cs b/hass-workstation-service/Program.cs index 3be2fbb..e22344e 100644 --- a/hass-workstation-service/Program.cs +++ b/hass-workstation-service/Program.cs @@ -19,6 +19,7 @@ using Microsoft.Win32; using JKang.IpcServiceFramework.Hosting; using hass_workstation_service.Communication.NamedPipe; using hass_workstation_service.Communication.InterProcesCommunication; +using hass_workstation_service.Domain.Notify; namespace hass_workstation_service { @@ -88,6 +89,7 @@ namespace hass_workstation_service services.AddSingleton(); services.AddSingleton(); services.AddHostedService(); + services.AddSingleton(); }).ConfigureIpcHost(builder => { // configure IPC endpoints diff --git a/hass-workstation-service/Worker.cs b/hass-workstation-service/Worker.cs index 4b13192..2e573c5 100644 --- a/hass-workstation-service/Worker.cs +++ b/hass-workstation-service/Worker.cs @@ -5,6 +5,7 @@ using System.Threading; using System.Threading.Tasks; using hass_workstation_service.Communication; using hass_workstation_service.Data; +using hass_workstation_service.Domain.Notify; using hass_workstation_service.Domain.Sensors; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; diff --git a/hass-workstation-service/hass-workstation-service.csproj b/hass-workstation-service/hass-workstation-service.csproj index 1fb7a53..3fc4d2a 100644 --- a/hass-workstation-service/hass-workstation-service.csproj +++ b/hass-workstation-service/hass-workstation-service.csproj @@ -44,6 +44,7 @@ +