From c91dd25353033add405e5f854dbfffc09abff218 Mon Sep 17 00:00:00 2001 From: sleevezipper Date: Wed, 30 Dec 2020 17:32:21 +0100 Subject: [PATCH] refactor so we don't need appsettings.json, further configure clickonce --- .vs/hass-workstation-service/v16/.suo | Bin 39936 -> 166912 bytes Communication/MQTT/MqttPublisher.cs | 20 ++++-- ...sorsService.cs => ConfigurationService.cs} | 58 ++++++++++++++---- Data/ConfiguredMqttBroker.cs | 12 ++++ Program.cs | 17 +---- .../PublishProfiles/ClickOnceProfile.pubxml | 13 ++-- Worker.cs | 20 +++--- hass-workstation-service.csproj | 1 + 8 files changed, 95 insertions(+), 46 deletions(-) rename Data/{ConfiguredSensorsService.cs => ConfigurationService.cs} (56%) create mode 100644 Data/ConfiguredMqttBroker.cs diff --git a/.vs/hass-workstation-service/v16/.suo b/.vs/hass-workstation-service/v16/.suo index 6372c1ee8045c6cbe8a77999d7e4b2b3aed4fc4d..a1e6dbc90c42a5123c8365a9783225d47b74b419 100644 GIT binary patch literal 166912 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

=g<83^*b)P>B#jz_}yG}?U~8a z1Ci67*ZoiD?>uAj;p~5WVI8S=r$fGN1?g|xexg^~+iC%Iy6rPR+WE52_Kf`Uo=3m& zstc|-?aY~n|M-{dHeb1TRsVawdU@$pUiDF1NWHTiw@yAy+~+C<(T9*oW4wI@`;h-W zFDaycfByh?_$XuWp@Iop^*UF|RI=sQ-B_EwskOP>tmffc04 zpPb4yo7^Y7f*xNq_jcg!h5Ws=Q|vp_2Qu&E$Et4xo_uw*DU7Rcy^Ofji zu2hLyZdi)|j9)h@wlOBWs3Pd_>qS{qSZ=I8gdbkv@!x6$#-t~8!X&!uLv z8$0$P=^QCqTRVHBG5&4r7^>x~m|5F8pRHBPsr<$cGmM^oNft6Nm!01_73-evneLnJ z?9BAUQr#)OKHJ#ZKzb&#m8wm2Y^b9XwIcJ>IQzyDUbuzN%Fr*r**166O@p8lxk;nB zY(8VAHLO1!V~ykt-q(#^uB6uzZuJY^H4b|3SwSt~-{NBKwq2u03rzUhV$TV#85%bA zHtVrc^D{tYoU&!U#ys)vS!7Xe-n6Nbp3NeUJX%;*T1blBl*t~-<~jYdsZg<2SOobE zaUPTSaoEc6_r_SDa3A_st#oZ}K2tngNkVC6YUyh9@PfGzUh?;nru;peTi}|N-c5&d zz8@sLTNQdeGEs}O2Nu%PJqMF^I-`XO1}v-nd2JXsD&_gf=xH=s-NZ!LVmVb_gpP}r zrWc4pGKANL;aHUOjp79dFSy%UzhExPSq@D$!cw1`Kpn|#D{;Tcpf4SJQWZL`H zQ@Q{988g^TSM|Spe0|F5e}`Y?*8kG4a@(bpA5D2tM-#?QR}jnI`-q|{{u#> BkSPEF delta 4190 zcmd^Cdu*H475~l`+x?t}<0MYv#!h1AP4je;zOp2B8n?7*8v{zKN<^q7F?~VPBzD)h zp>}AswzO-55A^b=AP59BK$RvyXu^hB^T(PZDAP1F39(4*zab{JMw>EG@0|FNAXcfc z3MTDJKi%`4bMLvw=bp#4|LJ)DyYgU}6{JN&FG-2?DHCpnLLrs_rWF45i33vsc{7xw zRnFB_dHw&W`}_}JVsRyU<&9dYl1Mc{%uIj*XJiAsfwQtxDI#7~j6alY#6xlYniAq< zsc|kY$7diigFvT+meQ;tkQI`OkU%gK*pzgdvk1J-PP3MfLP#RS6PVBIGKsblvI#ka zTtWqbn~k?c_|-JmM(E`^KG6MUQFRXxIB(SDsG_yaWXVomCS1h7e61|GBnovjh z8KIugKxibe2T4bDR8MGKm@)sop6I&?8weW-?9k}Kuwz$Q&=TLSVvEopUxxOC+N8_0 zYJxCHxOr)38U$`{mCm8CwH#fsa7DMysRbYw2TX*Wx?9Cz5nBX%(UaVYSBy4_@!4db z#!u3EHG1`4cm!wlK6n^CDZa#g#OC0u4Whe5(QQx59Q3PWK>a@D{pv$=t9h!5bL=3L}B;=J|}SQZ86W|WT3 z`S^_~6Nk(tRct0_A!i^**{z~0x)c9tE(iyQCEJ0WT0Oe6ElDihMZ0$s_K93l7!%nukG3Re}*keEN9Va#JV1?XS@7pi~hF9q+0S0(`T*Shk%^M_3r zK7T5|xcm6d#xZ?*4QRnadpX({_7|cj!>MrP;i?qjXFLf7=*jdY^4dcL9)Th^WTU6Z zsc;T*E-h#=<7|-+Oz0_gDqPXz#ZtUcT!Lo(_S*?b>~32sa$bX6vF9?_GFMb~J-FA^ z;qE1U(w64B_N~3Hp5Aux^&n)7ZQHnwe)v{HAZJP;|Ae?aMoh{v$`>d|a#|FwGRlG= z)q?)q4JxiEG3)V0u3y6esYvLxcr}(VIcM=gE_$pX4SSzL$eZWYa24=ScgUMd;L73U zA4;Oo&->JWLt=-)_m1_kxzdfmIi-G=6#W_RJ-P{}9;**jG^^*M zS9~@BM%+>H1+RfD^i=wime5K*mPZ`Ikrq{R)d~kX8!wT8gN>`ON?wBYHFj+YE#S%` zfW5??(3U>xpI10+D!aemNBNiUmhwt5wF4zTAFdH)vc_SYNTqa)57KlgBTqE zv+xao-Z1l3D8wC@M^v$BdJjs;13{+&pWIY-?lG`pft+IQm0VJfbWqwObr5wrj{0D9 zpDaG`Lp5l|X-WbZ6$2+>pZM$;Y#9IOC~O1qyG`k_H9~0G~;w}@- z(@s@h>}#gK6LGC_F-XGN zDyIv3t87T`+S}iMczsh%v!lkgu6*^Xm21muYen#J2#yC&gBQfe8L-cHTNVvhc`PsIH7e8HFn|j~Heb)+Iuw5^I zB@Ud1djz}=PnB{b50AVcKgL@L9NAQ<=0|UPXIF>k5!Zfq@43rh7l$VyK_pDVa@`Lr zW{sk8i~Qytz5Dy*`t+?-r}B(GYEzA?_u%&Fx2a| zf6PBcl6nsA>2S4+tHV%z?jn?kGeck${z^|cG x=wF82V&qqFNc5bPe}i|)iD<9Vi+i7k3VgiHi1$47V01k_08`cfwU%3)`fo=!+gktt diff --git a/Communication/MQTT/MqttPublisher.cs b/Communication/MQTT/MqttPublisher.cs index 76093d9..95d4894 100644 --- a/Communication/MQTT/MqttPublisher.cs +++ b/Communication/MQTT/MqttPublisher.cs @@ -3,6 +3,7 @@ using System.Text.Json; using System.Threading; using System.Threading.Tasks; using hass_workstation_service.Communication.Util; +using hass_workstation_service.Data; using Microsoft.Extensions.Logging; using MQTTnet; using MQTTnet.Client; @@ -16,31 +17,40 @@ namespace hass_workstation_service.Communication { private readonly IMqttClient _mqttClient; private readonly ILogger _logger; + private readonly ConfigurationService _configurationService; public DateTime LastConfigAnnounce { get; private set; } public DeviceConfigModel DeviceConfigModel { get; private set; } public bool IsConnected { get { - return this._mqttClient.IsConnected; + if (this._mqttClient == null) + { + return false; + } + else + { + return this._mqttClient.IsConnected; + } } } public MqttPublisher( ILogger logger, - IMqttClientOptions options, - DeviceConfigModel deviceConfigModel) + DeviceConfigModel deviceConfigModel, + ConfigurationService configurationService) { this._logger = logger; this.DeviceConfigModel = deviceConfigModel; + this._configurationService = configurationService; + var options = _configurationService.ReadMqttSettings().Result; var factory = new MqttFactory(); this._mqttClient = factory.CreateMqttClient(); - // connect to the broker - var result = this._mqttClient.ConnectAsync(options).Result; + this._mqttClient.ConnectAsync(options); // configure what happens on disconnect this._mqttClient.UseDisconnectedHandler(async e => { diff --git a/Data/ConfiguredSensorsService.cs b/Data/ConfigurationService.cs similarity index 56% rename from Data/ConfiguredSensorsService.cs rename to Data/ConfigurationService.cs index 08f1aa3..834f032 100644 --- a/Data/ConfiguredSensorsService.cs +++ b/Data/ConfigurationService.cs @@ -3,30 +3,30 @@ using System.Collections.Generic; using System.IO; using System.IO.IsolatedStorage; using System.Text.Json; +using System.Threading.Tasks; using hass_workstation_service.Communication; using hass_workstation_service.Domain.Sensors; using Microsoft.Extensions.Configuration; +using MQTTnet; +using MQTTnet.Client; +using MQTTnet.Client.Options; using Serilog; namespace hass_workstation_service.Data { - public class ConfiguredSensorsService + public class ConfigurationService { public ICollection ConfiguredSensors { get; private set; } - public IConfiguration Configuration { get; private set; } - private readonly MqttPublisher _publisher; private readonly IsolatedStorageFile _fileStorage; - public ConfiguredSensorsService(MqttPublisher publisher) + public ConfigurationService() { this._fileStorage = IsolatedStorageFile.GetUserStoreForApplication(); ConfiguredSensors = new List(); - _publisher = publisher; - ReadSettings(); } - public async void ReadSettings() + public async void ReadSensorSettings(MqttPublisher publisher) { IsolatedStorageFileStream stream = this._fileStorage.OpenFile("configured-sensors.json", FileMode.OpenOrCreate); Log.Logger.Information($"reading configured sensors from: {stream.Name}"); @@ -35,25 +35,53 @@ namespace hass_workstation_service.Data { sensors = await JsonSerializer.DeserializeAsync>(stream); } - + stream.Close(); foreach (ConfiguredSensor configuredSensor in sensors) { AbstractSensor sensor; - #pragma warning disable IDE0066 switch (configuredSensor.Type) { case "UserNotificationStateSensor": - sensor = new UserNotificationStateSensor(_publisher, configuredSensor.Name, configuredSensor.Id); + sensor = new UserNotificationStateSensor(publisher, configuredSensor.Name, configuredSensor.Id); break; case "DummySensor": - sensor = new DummySensor(_publisher, configuredSensor.Name, configuredSensor.Id); + sensor = new DummySensor(publisher, configuredSensor.Name, configuredSensor.Id); break; default: throw new InvalidOperationException("unsupported sensor type in config"); } this.ConfiguredSensors.Add(sensor); } + } + + public async Task ReadMqttSettings() + { + IsolatedStorageFileStream stream = this._fileStorage.OpenFile("mqttbroker.json", FileMode.OpenOrCreate); + Log.Logger.Information($"reading configured mqttbroker from: {stream.Name}"); + ConfiguredMqttBroker configuredBroker = null; + if (stream.Length > 0) + { + configuredBroker = await JsonSerializer.DeserializeAsync(stream); + } stream.Close(); + if (configuredBroker != null) + { + var mqttClientOptions = new MqttClientOptionsBuilder() + .WithTcpServer(configuredBroker.Host) + // .WithTls() + .WithCredentials(configuredBroker.Username, configuredBroker.Password.ToString()) + .Build(); + return mqttClientOptions; + } + else + { + //for now we return defaults until we can actually configure this + return new MqttClientOptionsBuilder() + .WithTcpServer("192.168.2.6") + // .WithTls() + .WithCredentials("tester", "tester") + .Build(); + } } public async void WriteSettings() @@ -64,7 +92,7 @@ namespace hass_workstation_service.Data foreach (AbstractSensor sensor in this.ConfiguredSensors) { - configuredSensorsToSave.Add(new ConfiguredSensor(){Id = sensor.Id, Name = sensor.Name, Type = sensor.GetType().Name}); + configuredSensorsToSave.Add(new ConfiguredSensor() { Id = sensor.Id, Name = sensor.Name, Type = sensor.GetType().Name }); } await JsonSerializer.SerializeAsync(stream, configuredSensorsToSave); @@ -76,5 +104,11 @@ namespace hass_workstation_service.Data this.ConfiguredSensors.Add(sensor); WriteSettings(); } + + public void AddConfiguredSensors(List sensors) + { + sensors.ForEach((sensor) => this.ConfiguredSensors.Add(sensor)); + WriteSettings(); + } } } \ No newline at end of file diff --git a/Data/ConfiguredMqttBroker.cs b/Data/ConfiguredMqttBroker.cs new file mode 100644 index 0000000..77afbc2 --- /dev/null +++ b/Data/ConfiguredMqttBroker.cs @@ -0,0 +1,12 @@ +using System; +using System.Security; + +namespace hass_workstation_service.Data +{ + public class ConfiguredMqttBroker + { + public string Host { get; set; } + public string Username { get; set; } + public SecureString Password { get; set; } + } +} \ No newline at end of file diff --git a/Program.cs b/Program.cs index 739f6f6..fe433b5 100644 --- a/Program.cs +++ b/Program.cs @@ -75,21 +75,8 @@ namespace hass_workstation_service public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .UseSerilog() - .ConfigureAppConfiguration((hostingContext, config) => - { - config - .SetBasePath(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)) - .AddJsonFile("appsettings.json"); - }) .ConfigureServices((hostContext, services) => { - IConfiguration configuration = hostContext.Configuration; - IConfigurationSection mqttSection = configuration.GetSection("MqttBroker"); - var mqttClientOptions = new MqttClientOptionsBuilder() - .WithTcpServer(mqttSection.GetValue("Host")) - // .WithTls() - .WithCredentials(mqttSection.GetValue("Username"), mqttSection.GetValue("Password")) - .Build(); var deviceConfig = new DeviceConfigModel { Name = Environment.MachineName, @@ -98,10 +85,8 @@ namespace hass_workstation_service Model = Environment.OSVersion.ToString(), Sw_version = Assembly.GetExecutingAssembly().GetName().Version.ToString() }; - services.AddSingleton(configuration); services.AddSingleton(deviceConfig); - services.AddSingleton(mqttClientOptions); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddHostedService(); }); diff --git a/Properties/PublishProfiles/ClickOnceProfile.pubxml b/Properties/PublishProfiles/ClickOnceProfile.pubxml index d7f87d1..e5e4a0c 100644 --- a/Properties/PublishProfiles/ClickOnceProfile.pubxml +++ b/Properties/PublishProfiles/ClickOnceProfile.pubxml @@ -4,7 +4,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. --> - 4 + 11 1.0.0.* True Release @@ -22,15 +22,20 @@ https://go.microsoft.com/fwlink/?LinkID=208121. bin\publish\ bin\publish\ ClickOnce - False - False + True + True win-x64 False sha256RSA True netcoreapp3.1 - False False Foreground + + + true + .NET Core Runtime 3.1.10 (x64) + + \ No newline at end of file diff --git a/Worker.cs b/Worker.cs index 0ff0a98..8e09eeb 100644 --- a/Worker.cs +++ b/Worker.cs @@ -15,20 +15,23 @@ namespace hass_workstation_service public class Worker : BackgroundService { private readonly ILogger _logger; - private readonly ConfiguredSensorsService _configuredSensorsService; + private readonly ConfigurationService _configurationService; private readonly MqttPublisher _mqttPublisher; public Worker(ILogger logger, - ConfiguredSensorsService configuredSensorsService, + ConfigurationService configuredSensorsService, MqttPublisher mqttPublisher) { _logger = logger; - this._configuredSensorsService = configuredSensorsService; + this._configurationService = configuredSensorsService; this._mqttPublisher = mqttPublisher; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { + _configurationService.ReadSensorSettings(_mqttPublisher); + + while (!_mqttPublisher.IsConnected) { _logger.LogInformation($"Connecting to MQTT broker..."); @@ -36,12 +39,11 @@ namespace hass_workstation_service } _logger.LogInformation("Connected. Sending auto discovery messages."); // if there are no configured sensors we add a dummy sensor - if (_configuredSensorsService.ConfiguredSensors.Count == 0) + if (_configurationService.ConfiguredSensors.Count == 0) { - _configuredSensorsService.AddConfiguredSensor(new DummySensor(_mqttPublisher)); - _configuredSensorsService.AddConfiguredSensor(new UserNotificationStateSensor(_mqttPublisher)); + _configurationService.AddConfiguredSensors(new List() { new DummySensor(_mqttPublisher), new UserNotificationStateSensor(_mqttPublisher) }); } - foreach (AbstractSensor sensor in _configuredSensorsService.ConfiguredSensors) + foreach (AbstractSensor sensor in _configurationService.ConfiguredSensors) { await sensor.PublishAutoDiscoveryConfigAsync(); } @@ -49,14 +51,14 @@ namespace hass_workstation_service { _logger.LogDebug("Worker running at: {time}", DateTimeOffset.Now); - foreach (AbstractSensor sensor in _configuredSensorsService.ConfiguredSensors) + foreach (AbstractSensor sensor in _configurationService.ConfiguredSensors) { await sensor.PublishStateAsync(); } // announce autodiscovery every 30 seconds if (_mqttPublisher.LastConfigAnnounce < DateTime.UtcNow.AddSeconds(-30)) { - foreach (AbstractSensor sensor in _configuredSensorsService.ConfiguredSensors) + foreach (AbstractSensor sensor in _configurationService.ConfiguredSensors) { await sensor.PublishAutoDiscoveryConfigAsync(); } diff --git a/hass-workstation-service.csproj b/hass-workstation-service.csproj index 6446513..8697e1d 100644 --- a/hass-workstation-service.csproj +++ b/hass-workstation-service.csproj @@ -4,6 +4,7 @@ netcoreapp3.1 dotnet-hass_workstation_service-C65C2EBE-1977-4C24-AC6B-6921877E1390 hass_workstation_service + WinExe