diff --git a/README.md b/README.md
index 3e4c6a2..8b5a81c 100644
--- a/README.md
+++ b/README.md
@@ -26,9 +26,14 @@ Note: You'll get a Windows Smartscreen warning because the code was self signed.
### Standalone
-You'll need [.NET 5 Runtime](https://dotnet.microsoft.com/download/dotnet/current/runtime) installed.
+If you don't want to use the installer, standalone is what you need. Make sure to install [.NET 5 Runtime](https://dotnet.microsoft.com/download/dotnet/current/runtime) first. Find the standalone version releases on GitHub [here](https://github.com/sleevezipper/hass-workstation-service/releases). Unpack all files to a folder and run `hass-workstation-service.exe`. This is the background service and you can use `UserInterface.exe` to configure the service. There is no automatic (or prompted) updating in the standalone version.
-If you don't want to use the installer, you can find the standalone version releases on GitHub [here](https://github.com/sleevezipper/hass-workstation-service/releases). Unpack all files to a folder and run `hass-workstation-service.exe`. This is the background service and you can use `UserInterface.exe` to configure the service. There is no automatic (or prompted) updating in the standalone version.
+### Getting Started
+
+As a prerequisite, make sure you have an MQTT username and password available. Using Home Assistant in combination with the Mosquitto broker add-on and integration? You can both use a Home Assistant account and a local account. From a security perspective, we recommend a local account as this only provides access to the MQTT Broker and not to your Home Assistant instance.
+
+Now that you are all set, make sure to run the `hass-workstation-service.exe` executable first. This executable is responsible for setting up the sensors and talking with your MQTT Broker. To configure the service, start the `UserInterface.exe` executable.
+Add your `hostname` or `IP address`, `port`, `username` and `password` and click on Save. In case you use the Mosquitto add-in, provide port `8883` and check `Use TLS`. The application will mention "All good" when configured correctly.
### Updating
@@ -38,6 +43,17 @@ If you used the installer, the app checks for updates on startup. If an update i
Find us on us on [Discord](https://discord.gg/VraYT2N3wd).
+## Development
+
+Want to develop or build the application yourself? Make sure to install the .NET Runtime [.NET 5 Runtime](https://dotnet.microsoft.com/download/dotnet/current/runtime) and [.NET 5 SDK](https://dotnet.microsoft.com/download/dotnet/current). Run the following commands from the `hass-workstation-service\hass-workstation-service` directory to get you started:
+
+```` powershell
+dotnet build
+dotnet publish
+````
+
+In case you are using Visual Studio Code, open the `hass-workstation-service\hass-workstation-service` folder to take advantage of the predefined build and publish tasks.
+
## Sensors
The application provides several sensors. Sensors can be configured with a name and this name will be used in the MQTT topic like this: `homeassistant/sensor/{DeviceName}/{Name}/state`. Sensors will expose themselves through [MQTT discovery](https://www.home-assistant.io/docs/mqtt/discovery/) and will automatically appear in Home assistant or any other platform that supports this type of configuration.
diff --git a/UserInterface/Views/AddCommandDialog.axaml b/UserInterface/Views/AddCommandDialog.axaml
index 0ea8d9f..c4f6639 100644
--- a/UserInterface/Views/AddCommandDialog.axaml
+++ b/UserInterface/Views/AddCommandDialog.axaml
@@ -5,9 +5,9 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="UserInterface.Views.AddCommandDialog"
SizeToContent="WidthAndHeight"
- Title="Add sensor">
+ Title="Add command">
- Sensor type
+ Command type
diff --git a/UserInterface/Views/AppInfo.axaml b/UserInterface/Views/AppInfo.axaml
index 5bbdfbc..33e766f 100644
--- a/UserInterface/Views/AppInfo.axaml
+++ b/UserInterface/Views/AppInfo.axaml
@@ -9,7 +9,7 @@
Info
-
+
diff --git a/UserInterface/Views/AppInfo.axaml.cs b/UserInterface/Views/AppInfo.axaml.cs
index 7a4c576..0fda95c 100644
--- a/UserInterface/Views/AppInfo.axaml.cs
+++ b/UserInterface/Views/AppInfo.axaml.cs
@@ -64,7 +64,7 @@ namespace UserInterface.Views
}
}
- public void Github(object sender, RoutedEventArgs args)
+ public void GitHub(object sender, RoutedEventArgs args)
{
BrowserUtil.OpenBrowser("https://github.com/sleevezipper/hass-workstation-service");
}
diff --git a/UserInterface/Views/BrokerSettings.axaml b/UserInterface/Views/BrokerSettings.axaml
index ee3df95..d583039 100644
--- a/UserInterface/Views/BrokerSettings.axaml
+++ b/UserInterface/Views/BrokerSettings.axaml
@@ -5,10 +5,10 @@
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
x:Class="UserInterface.Views.BrokerSettings">
- Mqtt broker
+ MQTT Broker
- IP or hostname
+ IP address or hostname
diff --git a/hass-workstation-service/Communication/InterProcesCommunication/InterProcessApi.cs b/hass-workstation-service/Communication/InterProcesCommunication/InterProcessApi.cs
index 95c4a6b..7dc486f 100644
--- a/hass-workstation-service/Communication/InterProcesCommunication/InterProcessApi.cs
+++ b/hass-workstation-service/Communication/InterProcesCommunication/InterProcessApi.cs
@@ -75,7 +75,7 @@ namespace hass_workstation_service.Communication.InterProcesCommunication
public List GetConfiguredSensors()
{
- return this._configurationService.ConfiguredSensors.Select(s => new ConfiguredSensorModel() { Name = s.Name, Type = s.GetType().Name, Value = s.PreviousPublishedState, Id = s.Id, UpdateInterval = s.UpdateInterval, UnitOfMeasurement = s.GetAutoDiscoveryConfig().Unit_of_measurement }).ToList();
+ return this._configurationService.ConfiguredSensors.Select(s => new ConfiguredSensorModel() { Name = s.Name, Type = s.GetType().Name, Value = s.PreviousPublishedState, Id = s.Id, UpdateInterval = s.UpdateInterval, UnitOfMeasurement = ((SensorDiscoveryConfigModel)s.GetAutoDiscoveryConfig()).Unit_of_measurement }).ToList();
}
public List GetConfiguredCommands()
diff --git a/hass-workstation-service/Communication/MQTT/MqttPublisher.cs b/hass-workstation-service/Communication/MQTT/MqttPublisher.cs
index b431d90..bcdd12f 100644
--- a/hass-workstation-service/Communication/MQTT/MqttPublisher.cs
+++ b/hass-workstation-service/Communication/MQTT/MqttPublisher.cs
@@ -7,6 +7,7 @@ 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;
using hass_workstation_service.Domain.Commands;
using Microsoft.Extensions.Logging;
using MQTTnet;
@@ -95,8 +96,9 @@ namespace hass_workstation_service.Communication
this._logger.LogInformation($"Message dropped because mqtt not connected: {message}");
}
}
-
- public async Task AnnounceAutoDiscoveryConfig(DiscoveryConfigModel config, string domain, bool clearConfig = false)
+ // TODO: This should take a sensor/command instead of a config.
+ // Then we can ask the sensor about the topic based on ObjectId instead of referencing Name directly
+ public async Task AnnounceAutoDiscoveryConfig(AbstractDiscoverable discoverable, string domain, bool clearConfig = false)
{
if (this._mqttClient.IsConnected)
{
@@ -109,8 +111,8 @@ namespace hass_workstation_service.Communication
};
var message = new MqttApplicationMessageBuilder()
- .WithTopic($"homeassistant/{domain}/{this.DeviceConfigModel.Name}/{config.Name}/config")
- .WithPayload(clearConfig ? "" : JsonSerializer.Serialize(config, config.GetType(), options))
+ .WithTopic($"homeassistant/{domain}/{this.DeviceConfigModel.Name}/{discoverable.ObjectId}/config")
+ .WithPayload(clearConfig ? "" : JsonSerializer.Serialize(discoverable.GetAutoDiscoveryConfig(), discoverable.GetAutoDiscoveryConfig().GetType(), options))
.WithRetainFlag()
.Build();
await this.Publish(message);
@@ -177,7 +179,7 @@ namespace hass_workstation_service.Communication
{
if (this.IsConnected)
{
- await this._mqttClient.SubscribeAsync(command.GetAutoDiscoveryConfig().Command_topic);
+ await this._mqttClient.SubscribeAsync(((CommandDiscoveryConfigModel) command.GetAutoDiscoveryConfig()).Command_topic);
}
else
{
@@ -186,7 +188,7 @@ namespace hass_workstation_service.Communication
await Task.Delay(5500);
}
- await this._mqttClient.SubscribeAsync(command.GetAutoDiscoveryConfig().Command_topic);
+ await this._mqttClient.SubscribeAsync(((CommandDiscoveryConfigModel) command.GetAutoDiscoveryConfig()).Command_topic);
}
@@ -197,7 +199,7 @@ namespace hass_workstation_service.Communication
{
foreach (AbstractCommand command in this.Subscribers)
{
- if (command.GetAutoDiscoveryConfig().Command_topic == applicationMessage.Topic)
+ if (((CommandDiscoveryConfigModel)command.GetAutoDiscoveryConfig()).Command_topic == applicationMessage.Topic)
{
if (Encoding.UTF8.GetString(applicationMessage?.Payload) == "ON")
{
diff --git a/hass-workstation-service/Communication/MQTT/SensorDiscoveryConfigModel.cs b/hass-workstation-service/Communication/MQTT/SensorDiscoveryConfigModel.cs
index 1c5218d..3d942e1 100644
--- a/hass-workstation-service/Communication/MQTT/SensorDiscoveryConfigModel.cs
+++ b/hass-workstation-service/Communication/MQTT/SensorDiscoveryConfigModel.cs
@@ -15,6 +15,11 @@ namespace hass_workstation_service.Communication
///
///
public string Name { get; set; }
+ ///
+ /// The MQTT topic subscribed to receive sensor values.
+ ///
+ ///
+ public string State_topic { get; set; }
}
public class SensorDiscoveryConfigModel : DiscoveryConfigModel
{
@@ -69,12 +74,6 @@ namespace hass_workstation_service.Communication
///
///
public int? Qos { get; set; }
-
- ///
- /// The MQTT topic subscribed to receive sensor values.
- ///
- ///
- public string State_topic { get; set; }
///
/// (Optional) An ID that uniquely identifies this sensor. If two sensors have the same unique ID, Home Assistant will raise an exception.
///
@@ -147,11 +146,6 @@ namespace hass_workstation_service.Communication
///
public int? Qos { get; set; }
///
- /// The MQTT topic subscribed to receive sensor values.
- ///
- ///
- public string State_topic { get; set; }
- ///
/// (Optional) An ID that uniquely identifies this sensor. If two sensors have the same unique ID, Home Assistant will raise an exception.
///
///
diff --git a/hass-workstation-service/Domain/AbstractDiscoverable.cs b/hass-workstation-service/Domain/AbstractDiscoverable.cs
index 7c388f7..aba479e 100644
--- a/hass-workstation-service/Domain/AbstractDiscoverable.cs
+++ b/hass-workstation-service/Domain/AbstractDiscoverable.cs
@@ -1,7 +1,9 @@
-using System;
+using hass_workstation_service.Communication;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
+using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace hass_workstation_service.Domain
@@ -9,5 +11,17 @@ namespace hass_workstation_service.Domain
public abstract class AbstractDiscoverable
{
public abstract string Domain { get; }
+ public string Name { get; protected set; }
+
+ public string ObjectId
+ {
+ get
+ {
+ return Regex.Replace(this.Name, "[^a-zA-Z0-9_-]", "_");
+ }
+ }
+ public Guid Id { get; protected set; }
+
+ public abstract DiscoveryConfigModel GetAutoDiscoveryConfig();
}
}
diff --git a/hass-workstation-service/Domain/Commands/AbstractCommand.cs b/hass-workstation-service/Domain/Commands/AbstractCommand.cs
index b1b30e6..849077e 100644
--- a/hass-workstation-service/Domain/Commands/AbstractCommand.cs
+++ b/hass-workstation-service/Domain/Commands/AbstractCommand.cs
@@ -8,8 +8,6 @@ namespace hass_workstation_service.Domain.Commands
public abstract class AbstractCommand : AbstractDiscoverable
{
- public Guid Id { get; protected set; }
- public string Name { get; protected set; }
///
/// The update interval in seconds. It checks state only if the interval has passed.
///
@@ -40,7 +38,6 @@ namespace hass_workstation_service.Domain.Commands
return config;
}
- public abstract CommandDiscoveryConfigModel GetAutoDiscoveryConfig();
public abstract string GetState();
public async Task PublishStateAsync()
@@ -68,11 +65,11 @@ namespace hass_workstation_service.Domain.Commands
}
public async void PublishAutoDiscoveryConfigAsync()
{
- await this.Publisher.AnnounceAutoDiscoveryConfig(this.GetAutoDiscoveryConfig(), this.Domain);
+ await this.Publisher.AnnounceAutoDiscoveryConfig(this, this.Domain);
}
public async Task UnPublishAutoDiscoveryConfigAsync()
{
- await this.Publisher.AnnounceAutoDiscoveryConfig(this.GetAutoDiscoveryConfig(), this.Domain, true);
+ await this.Publisher.AnnounceAutoDiscoveryConfig(this, this.Domain, true);
}
public abstract void TurnOn();
public abstract void TurnOff();
diff --git a/hass-workstation-service/Domain/Sensors/AbstractSensor.cs b/hass-workstation-service/Domain/Sensors/AbstractSensor.cs
index 8c5cd50..22d9a37 100644
--- a/hass-workstation-service/Domain/Sensors/AbstractSensor.cs
+++ b/hass-workstation-service/Domain/Sensors/AbstractSensor.cs
@@ -1,4 +1,5 @@
using System;
+using System.Text.RegularExpressions;
using System.Threading.Tasks;
using hass_workstation_service.Communication;
using MQTTnet;
@@ -8,8 +9,6 @@ namespace hass_workstation_service.Domain.Sensors
public abstract class AbstractSensor : AbstractDiscoverable
{
- public Guid Id { get; protected set; }
- public string Name { get; protected set; }
///
/// The update interval in seconds. It checks state only if the interval has passed.
///
@@ -40,7 +39,6 @@ namespace hass_workstation_service.Domain.Sensors
return config;
}
- public abstract SensorDiscoveryConfigModel GetAutoDiscoveryConfig();
public abstract string GetState();
public async Task PublishStateAsync()
@@ -68,11 +66,11 @@ namespace hass_workstation_service.Domain.Sensors
}
public async void PublishAutoDiscoveryConfigAsync()
{
- await this.Publisher.AnnounceAutoDiscoveryConfig(this.GetAutoDiscoveryConfig(), this.Domain);
+ await this.Publisher.AnnounceAutoDiscoveryConfig(this, this.Domain);
}
public async Task UnPublishAutoDiscoveryConfigAsync()
{
- await this.Publisher.AnnounceAutoDiscoveryConfig(this.GetAutoDiscoveryConfig(), this.Domain, true);
+ await this.Publisher.AnnounceAutoDiscoveryConfig(this, this.Domain, true);
}
}
diff --git a/hass-workstation-service/Domain/Sensors/DummySensor.cs b/hass-workstation-service/Domain/Sensors/DummySensor.cs
index 3431fb5..66eaaad 100644
--- a/hass-workstation-service/Domain/Sensors/DummySensor.cs
+++ b/hass-workstation-service/Domain/Sensors/DummySensor.cs
@@ -20,7 +20,7 @@ namespace hass_workstation_service.Domain.Sensors
Name = this.Name,
Unique_id = this.Id.ToString(),
Device = this.Publisher.DeviceConfigModel,
- State_topic = $"homeassistant/{this.Domain}/{Publisher.DeviceConfigModel.Name}/{this.Name}/state",
+ State_topic = $"homeassistant/{this.Domain}/{Publisher.DeviceConfigModel.Name}/{this.ObjectId}/state",
Availability_topic = $"homeassistant/{this.Domain}/{Publisher.DeviceConfigModel.Name}/availability"
});
}