Skip to content

Commit

Permalink
Merge pull request #27 from JonasMH/develop
Browse files Browse the repository at this point in the history
Add readme, examples and more discoverydocs.
  • Loading branch information
JonasMH authored Jan 10, 2024
2 parents 8c4ecab + bf7af0a commit 6a5f28c
Show file tree
Hide file tree
Showing 63 changed files with 1,520 additions and 194 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
- name: Setup .NET Core
uses: actions/setup-dotnet@v3
with:
dotnet-version: 8.x
dotnet-version: "8.0.100"
cache: true
cache-dependency-path: src/ToMqttNet/packages.lock.json
- name: Restore
Expand Down Expand Up @@ -73,7 +73,7 @@ jobs:
- name: Setup .NET Core
uses: actions/setup-dotnet@v3
with:
dotnet-version: 8.x
dotnet-version: "8.0.100"
cache: true
cache-dependency-path: src/ToMqttNet/packages.lock.json
- name: Create Release NuGet package
Expand Down
152 changes: 152 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
# HomeAssistantDiscoveryNet

This project contains two libraries that are both published to Nuget

1. `HomeAssistantDiscoveryNet` Library, contains all HA Discovery Documents
2. `ToMqttNet` a managed way to keep a MQTT connection in ASP.NET

## HomeAssistantDiscoveryNet Library

Contains the following (Home Assistant MQTT Discovery Documents)[https://www.home-assistant.io/integrations/mqtt/#mqtt-discovery] as C\# classes:

- AlarmControlPanel
- BinarySensor
- Button
- Camera
- Climate
- Cover
- DefaultLight
- DeviceTracker
- DeviceTrigger
- Event
- Fan
- Humidifier
- Image
- JsonLight
- LawnMower
- Lock
- Number
- Scene
- Select
- Sensor
- Siren
- Switch
- TagScanner
- TemplateLight
- Text
- Update
- Vacuum
- Valve
- WaterHeater

This makes it easy to create discovery documents from C\# without having to worry about mistyping property names etc.

It also including de(serilization) using `System.Text.Json` source generators (AoT Compatible)

### How to serialize discovery docs

```csharp
var cfg = new MqttBinarySensorDiscoveryConfig
{
Name = $"Recommend Charging",
ValueTemplate = "{{ 'ON' if value_json.recommend else 'OFF' }}",
StateTopic = $"some-node/status/recommend-charging",
UniqueId = $"some-node-recommend-charging",
};

var json = cfg.ToJson();
```

Results in

```json
{
"component": "binary_sensor",
"state_topic": "some-node/status/recommend-charging",
"value_template": "{{ 'ON' if value_json.recommend else 'OFF' }}",
"name": "Recommend Charging",
"unique_id": "some-node-recommend-charging"
}
```

### How to deserialize discovery docs

```csharp
var parser = new MqttDiscoveryConfigParser(NullLoggerFactory.Instance, []);
var topic = "some-node/binary/some_sensor";
var message = "{\"component\": \"binary_sensor\", \"state_topic\": \"some-node/status/recommend-charging\", \"value_template\": \"{{ 'ON' if value_json.recommend else 'OFF' }}\", \"name\": \"Recommend Charging\", \"unique_id\": \"some-node-recommend-charging\"}";

var result = parser.Parse(topic, message);

Assert.IsType<MqttBinarySensorDiscoveryConfig>(result);
```

## ToMqttNet Library

This sets up a managed connection to a MQTT broker with

- Makes use of [MQTTnet](https://github.com/dotnet/MQTTnet) for the connection
- Dependency injection
- `System.Diagnostics.Metrics` Based metrics
- AoT compatible
- Home Assistant Discovery integration

### How to set up the ToMqttNet Library

In `Program.cs`/`Startup.cs`

```csharp
var builder = WebApplication.CreateSlimBuilder(args);

builder.Services.AddMqttConnection()
.Configure<IOptions<MqttOptions>>((options, mqttConfI) =>
{
var mqttConf = mqttConfI.Value;
options.NodeId = "myintegration";
options.ClientOptions.ChannelOptions = new MqttClientTcpOptions
{
Server = mqttConf.Server,
Port = mqttConf.Port,
};
});

// ...
```

### How to use the ToMqttNet Library

```csharp
// Remember to register this service in ASP.NET (Or call the .Execute)
public class CounterMqttBackgroundService(MqttConnectionService mqtt) : BackgroundService
{
private readonly MqttConnectionService _mqtt = mqtt;

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
var discoveryDoc = new MqttSensorDiscoveryConfig()
{
UniqueId = "myintegration_mycounter",
Name = "My Counter",
ValueTemplate = "{{ value_json.value }}",
StateTopic = _mqtt.MqttOptions.NodeId + "/status/counter", // myintegration/status/counter
};

await _mqtt.PublishDiscoveryDocument(discoveryDoc);

var counter = 0L;
while (!stoppingToken.IsCancellationRequested)
{
await _mqtt.PublishAsync(new MqttApplicationMessageBuilder()
.WithTopic(_mqtt.MqttOptions.NodeId + "/status/counter")
.WithPayload(JsonSerializer.Serialize(new {value = counter}))
.Build());
await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
counter++;
}
}
}
```

## Examples / usages of HomeAssistantDiscoveryNet and ToMqttNet

- [JonasMH/Dantherm2Mqtt](https://github.com/JonasMH/Dantherm2Mqtt)
8 changes: 7 additions & 1 deletion ToMqttNet.sln
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ VisualStudioVersion = 17.1.32104.313
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ToMqttNet", "src\ToMqttNet\ToMqttNet.csproj", "{EBAC9526-DC18-4B97-931F-1962ABE0CA6D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ToMqttNet.Test.Unit", "test\ToMqttNet.Test.Unit\ToMqttNet.Test.Unit.csproj", "{B94A03BA-1137-4F1B-8FE1-99CFFF37A41A}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ToMqttNet.Test.Unit", "test\ToMqttNet.Test.Unit\ToMqttNet.Test.Unit.csproj", "{B94A03BA-1137-4F1B-8FE1-99CFFF37A41A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HomeAssistantDiscoveryNet", "src\HomeAssistantDiscoveryNet\HomeAssistantDiscoveryNet.csproj", "{6B17165D-A7C1-48FA-ACAD-F5787C117D09}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand All @@ -21,6 +23,10 @@ Global
{B94A03BA-1137-4F1B-8FE1-99CFFF37A41A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B94A03BA-1137-4F1B-8FE1-99CFFF37A41A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B94A03BA-1137-4F1B-8FE1-99CFFF37A41A}.Release|Any CPU.Build.0 = Release|Any CPU
{6B17165D-A7C1-48FA-ACAD-F5787C117D09}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6B17165D-A7C1-48FA-ACAD-F5787C117D09}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6B17165D-A7C1-48FA-ACAD-F5787C117D09}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6B17165D-A7C1-48FA-ACAD-F5787C117D09}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;

namespace ToMqttNet;
namespace HomeAssistantDiscoveryNet;

/// <summary>
/// The mqtt alarm panel platform enables the possibility to control MQTT capable alarm panels. The Alarm icon will change state after receiving a new state from state_topic. If these messages are published with RETAIN flag, the MQTT alarm panel will receive an instant state update after subscription and will start with the correct state. Otherwise, the initial state will be unknown.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;

namespace ToMqttNet;
namespace HomeAssistantDiscoveryNet;

/// <summary>
/// The mqtt binary sensor platform uses an MQTT message received to set the binary sensor’s state to on or off.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
using System.Text.Json.Serialization;

namespace ToMqttNet;
namespace HomeAssistantDiscoveryNet;

/// <summary>
/// The mqtt button platform lets you send an MQTT message when the button is pressed in the frontend or the button press service is called. This can be used to expose some service of a remote device, for example reboot.
/// </summary>
public class MqttButtonDiscoveryConfig : MqttDiscoveryConfig
/// <summary>
/// The mqtt button platform lets you send an MQTT message when the button is pressed in the frontend or the button press service is called. This can be used to expose some service of a remote device, for example reboot.
/// </summary>
public class MqttButtonDiscoveryConfig : MqttDiscoveryConfig
{
public override string Component => "button";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;

namespace ToMqttNet;
namespace HomeAssistantDiscoveryNet;

/// <summary>
/// The mqtt camera platform allows you to integrate the content of an image file sent through MQTT into Home Assistant as a camera. Every time a message under the topic in the configuration is received, the image displayed in Home Assistant will also be updated.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;

namespace ToMqttNet;
namespace HomeAssistantDiscoveryNet;

/// <summary>
/// The mqtt climate platform lets you control your MQTT enabled HVAC devices.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;

namespace ToMqttNet;
namespace HomeAssistantDiscoveryNet;

/// <summary>
/// The mqtt cover platform allows you to control an MQTT cover(such as blinds, a roller shutter or a garage door).
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;

namespace ToMqttNet;
namespace HomeAssistantDiscoveryNet;

/// <summary>
/// The mqtt light platform lets you control your MQTT enabled lights through one of the supported message schemas, default, json or template.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;

namespace ToMqttNet;
namespace HomeAssistantDiscoveryNet;

/// <summary>
/// The mqtt device tracker platform allows you to define new device_trackers through manual YAML configuration in configuration.yaml and also to automatically discover device_trackers through a discovery schema using the MQTT Discovery protocol.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;

namespace ToMqttNet;
namespace HomeAssistantDiscoveryNet;

/// <summary>
/// The mqtt device trigger platform uses an MQTT message payload to generate device trigger events.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;

namespace ToMqttNet;
namespace HomeAssistantDiscoveryNet;

public class MqttEventDiscoveryConfig : MqttDiscoveryConfig
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;

namespace ToMqttNet;
namespace HomeAssistantDiscoveryNet;

/// <summary>
/// The mqtt fan platform lets you control your MQTT enabled fans.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;

namespace ToMqttNet;
namespace HomeAssistantDiscoveryNet;

/// <summary>
/// The mqtt humidifier platform lets you control your MQTT enabled humidifiers.
Expand Down
85 changes: 85 additions & 0 deletions src/HomeAssistantDiscoveryNet/Entities/MqttImageDiscoveryConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
using System.Text.Json.Serialization;

namespace HomeAssistantDiscoveryNet;

/// <summary>
/// The mqtt image platform allows you to integrate the content of an image file sent through MQTT into Home Assistant as an image. The image platform is a simplified version of the camera platform that only accepts images. Every time a message under the image_topic in the configuration is received, the image displayed in Home Assistant will also be updated. Messages received on image_topic should contain the full contents of an image file, for example, a JPEG image, without any additional encoding or metadata.
/// </summary>
public class MqttImageDiscoveryConfig : MqttDiscoveryConfig
{
public override string Component => "image";

///<summary>
/// The content type of and image data message received on image_topic. This option cannot be used with the url_topic because the content type is derived when downloading the image.
/// , default: image/jpeg
///</summary>
[JsonPropertyName("content_type")]
public string? ContentType { get; set; }

///<summary>
/// Flag which defines if the entity should be enabled when first added.
/// , default: true
///</summary>
[JsonPropertyName("enabled_by_default")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public bool? EnabledByDefault { get; set; }

///<summary>
/// The encoding of the payloads received. Set to "" to disable decoding of incoming payload. Use image_encoding to enable Base64 decoding on image_topic.
/// , default: utf-8
///</summary>
[JsonPropertyName("encoding")]
public string? Encoding { get; set; }

///<summary>
/// The category of the entity.
/// , default: None
///</summary>
[JsonPropertyName("entity_category")]
public string? EntityCategory { get; set; }

///<summary>
/// The encoding of the image payloads received. Set to "b64" to enable base64 decoding of image payload. If not set, the image payload must be raw binary data.
/// , default: None
///</summary>
[JsonPropertyName("image_encoding")]
public string? ImageEncoding { get; set; }

///<summary>
/// The MQTT topic to subscribe to receive the image payload of the image to be downloaded. Ensure the content_type type option is set to the corresponding content type. This option cannot be used together with the url_topic option. But at least one of these option is required.
///</summary>
[JsonPropertyName("image_topic")]
public string? ImageTopic { get; set; }

///<summary>
/// Defines a template to extract the JSON dictionary from messages received on the json_attributes_topic.
///</summary>
[JsonPropertyName("json_attributes_template")]
public string? JsonAttributesTemplate { get; set; }

///<summary>
/// The MQTT topic subscribed to receive a JSON dictionary payload and then set as sensor attributes. Implies force_update of the current sensor state when a message is received on this topic.
///</summary>
[JsonPropertyName("json_attributes_topic")]
public string? JsonAttributesTopic { get; set; }

///<summary>
/// Used instead of name for automatic generation of entity_id
///</summary>
[JsonPropertyName("object_id")]
public string? ObjectId { get; set; }

///<summary>
/// Defines a template to extract the image URL from a message received at url_topic.
///</summary>
[JsonPropertyName("url_template")]
public string? UrlTemplate { get; set; }

///<summary>
/// The MQTT topic to subscribe to receive an image URL. A url_template option can extract the URL from the message. The content_type will be derived from the image when downloaded. This option cannot be used together with the image_topic option, but at least one of these options is required.
///</summary>
[JsonPropertyName("url_topic")]
public string? UrlTopic { get; set; }
}


Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;

namespace ToMqttNet;
namespace HomeAssistantDiscoveryNet;

/// <summary>
/// The mqtt light platform lets you control your MQTT enabled lights through one of the supported message schemas, default, json or template.
Expand Down
Loading

0 comments on commit 6a5f28c

Please sign in to comment.