Skip to content

Smdn.TPSmartHomeDevices.Kasa version 1.0.0

Compare
Choose a tag to compare
@smdn smdn released this 02 May 15:42
· 183 commits to main since this release
6c7eef8

Released package

Release notes

The full release notes are available at gist.

Change log

Change log in this release:

API changes

API changes in this release:
diff --git a/doc/api-list/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa-net6.0.apilist.cs b/doc/api-list/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa-net6.0.apilist.cs
index 3ae57ff..f6d9649 100644
--- a/doc/api-list/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa-net6.0.apilist.cs
+++ b/doc/api-list/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa-net6.0.apilist.cs
@@ -1,220 +1,226 @@
-// Smdn.TPSmartHomeDevices.Kasa.dll (Smdn.TPSmartHomeDevices.Kasa-1.0.0-rc1)
+// Smdn.TPSmartHomeDevices.Kasa.dll (Smdn.TPSmartHomeDevices.Kasa-1.0.0)
 //   Name: Smdn.TPSmartHomeDevices.Kasa
 //   AssemblyVersion: 1.0.0.0
-//   InformationalVersion: 1.0.0-rc1+00727d1f82dcb2b9dd9c6e586f6c54110349bf48
+//   InformationalVersion: 1.0.0+4dd7eda1e01a411bacbd6593ca050a45b3c57c37
 //   TargetFramework: .NETCoreApp,Version=v6.0
 //   Configuration: Release
 //   Referenced assemblies:
 //     Microsoft.Extensions.DependencyInjection.Abstractions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
 //     Microsoft.Extensions.Logging.Abstractions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
 //     Microsoft.Win32.Primitives, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
 //     Smdn.TPSmartHomeDevices.Primitives, Version=1.0.0.0, Culture=neutral
 //     System.Collections, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
 //     System.ComponentModel, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
 //     System.Memory, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
 //     System.Net.NetworkInformation, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
 //     System.Net.Primitives, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
 //     System.Net.Sockets, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
 //     System.Runtime, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
 //     System.Text.Encodings.Web, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
 //     System.Text.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
 #nullable enable annotations
 
 using System;
 using System.Buffers;
 using System.Diagnostics.CodeAnalysis;
 using System.Net;
 using System.Net.NetworkInformation;
 using System.Text.Json;
 using System.Text.Json.Serialization;
 using System.Threading;
 using System.Threading.Tasks;
+using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Logging;
 using Smdn.TPSmartHomeDevices;
 using Smdn.TPSmartHomeDevices.Kasa;
 using Smdn.TPSmartHomeDevices.Kasa.Protocol;
 
 namespace Smdn.TPSmartHomeDevices.Kasa {
   public class HS105 : KasaDevice {
     public static HS105 Create<TAddress>(TAddress deviceAddress, IServiceProvider serviceProvider) where TAddress : notnull {}
 
     public HS105(IDeviceEndPoint deviceEndPoint, IServiceProvider? serviceProvider = null) {}
     public HS105(IPAddress ipAddress, IServiceProvider? serviceProvider = null) {}
     public HS105(PhysicalAddress macAddress, IServiceProvider serviceProvider) {}
     public HS105(string host, IServiceProvider? serviceProvider = null) {}
 
     public ValueTask<bool> GetOnOffStateAsync(CancellationToken cancellationToken = default) {}
     public ValueTask SetOnOffStateAsync(bool newOnOffState, CancellationToken cancellationToken = default) {}
     public ValueTask TurnOffAsync(CancellationToken cancellationToken = default) {}
     public ValueTask TurnOnAsync(CancellationToken cancellationToken = default) {}
   }
 
   public class KL130 : KasaDevice {
     public static KL130 Create<TAddress>(TAddress deviceAddress, IServiceProvider serviceProvider) where TAddress : notnull {}
 
     public KL130(IDeviceEndPoint deviceEndPoint, IServiceProvider? serviceProvider = null) {}
     public KL130(IPAddress ipAddress, IServiceProvider? serviceProvider = null) {}
     public KL130(PhysicalAddress macAddress, IServiceProvider serviceProvider) {}
     public KL130(string host, IServiceProvider? serviceProvider = null) {}
 
     public ValueTask<KL130LightState> GetLightStateAsync(CancellationToken cancellationToken = default) {}
     public ValueTask<bool> GetOnOffStateAsync(CancellationToken cancellationToken = default) {}
     public ValueTask SetColorAsync(int hue, int saturation, int? brightness = null, TimeSpan? transitionPeriod = null, CancellationToken cancellationToken = default) {}
     public ValueTask SetColorTemperatureAsync(int colorTemperature, int? brightness = null, TimeSpan? transitionPeriod = null, CancellationToken cancellationToken = default) {}
     public ValueTask SetOnOffStateAsync(bool newOnOffState, TimeSpan? transitionPeriod = null, CancellationToken cancellationToken = default) {}
     public ValueTask TurnOffAsync(TimeSpan? transitionPeriod = null, CancellationToken cancellationToken = default) {}
     public ValueTask TurnOnAsync(TimeSpan? transitionPeriod = null, CancellationToken cancellationToken = default) {}
   }
 
   public class KasaDevice : IDisposable {
     protected readonly struct NullParameter {
     }
 
     protected static readonly JsonEncodedText MethodTextGetSysInfo; // = "get_sysinfo"
     protected static readonly JsonEncodedText ModuleTextSystem; // = "system"
 
     public static KasaDevice Create(IDeviceEndPoint deviceEndPoint, IServiceProvider? serviceProvider = null) {}
     public static KasaDevice Create(IPAddress ipAddress, IServiceProvider? serviceProvider = null) {}
     public static KasaDevice Create(PhysicalAddress macAddress, IServiceProvider serviceProvider) {}
     public static KasaDevice Create(string host, IServiceProvider? serviceProvider = null) {}
     public static KasaDevice Create<TAddress>(TAddress deviceAddress, IServiceProvider serviceProvider) where TAddress : notnull {}
 
-    protected KasaDevice(IDeviceEndPoint deviceEndPoint, IServiceProvider? serviceProvider = null) {}
-    protected KasaDevice(IPAddress ipAddress, IServiceProvider? serviceProvider = null) {}
+    protected KasaDevice(IDeviceEndPoint deviceEndPoint, IServiceProvider? serviceProvider) {}
+    protected KasaDevice(IPAddress ipAddress, IServiceProvider? serviceProvider) {}
     protected KasaDevice(PhysicalAddress macAddress, IServiceProvider serviceProvider) {}
-    protected KasaDevice(string host, IServiceProvider? serviceProvider = null) {}
+    protected KasaDevice(string host, IServiceProvider? serviceProvider) {}
 
     public bool IsConnected { get; }
     [MemberNotNullWhen(false, "deviceEndPoint")]
     protected bool IsDisposed { [MemberNotNullWhen(false, "deviceEndPoint")] get; }
 
     protected virtual void Dispose(bool disposing) {}
     public void Dispose() {}
     public ValueTask<EndPoint> ResolveEndPointAsync(CancellationToken cancellationToken = default) {}
     protected ValueTask SendRequestAsync<TMethodParameter>(JsonEncodedText module, JsonEncodedText method, TMethodParameter parameters, CancellationToken cancellationToken) {}
     protected ValueTask<TMethodResult> SendRequestAsync<TMethodParameter, TMethodResult>(JsonEncodedText module, JsonEncodedText method, TMethodParameter parameters, Func<JsonElement, TMethodResult> composeResult, CancellationToken cancellationToken) {}
     protected ValueTask<TMethodResult> SendRequestAsync<TMethodResult>(JsonEncodedText module, JsonEncodedText method, Func<JsonElement, TMethodResult> composeResult, CancellationToken cancellationToken) {}
+    public override string? ToString() {}
   }
 
   public abstract class KasaDeviceExceptionHandler {
     internal protected static readonly KasaDeviceExceptionHandler Default; // = "Smdn.TPSmartHomeDevices.Kasa.KasaDeviceDefaultExceptionHandler"
 
     protected KasaDeviceExceptionHandler() {}
 
     public abstract KasaDeviceExceptionHandling DetermineHandling(KasaDevice device, Exception exception, int attempt, ILogger? logger);
   }
 
+  public static class KasaDeviceExceptionHandlerServiceCollectionExtensions {
+    public static IServiceCollection AddKasaDeviceExceptionHandler(this IServiceCollection services, KasaDeviceExceptionHandler exceptionHandler) {}
+  }
+
   public class KasaDisconnectedException : KasaProtocolException {
     public KasaDisconnectedException(string message, EndPoint deviceEndPoint, Exception? innerException) {}
   }
 
   public class KasaErrorResponseException : KasaUnexpectedResponseException {
     public KasaErrorResponseException(EndPoint deviceEndPoint, string requestModule, string requestMethod, int rawErrorCode) {}
 
     public int RawErrorCode { get; }
   }
 
   public class KasaIncompleteResponseException : KasaUnexpectedResponseException {
     public KasaIncompleteResponseException(string message, EndPoint deviceEndPoint, string requestModule, string requestMethod, Exception? innerException) {}
   }
 
   public abstract class KasaProtocolException : InvalidOperationException {
     protected KasaProtocolException(string message, EndPoint deviceEndPoint, Exception? innerException) {}
 
     public EndPoint DeviceEndPoint { get; }
   }
 
   public class KasaUnexpectedResponseException : KasaProtocolException {
     public KasaUnexpectedResponseException(string message, EndPoint deviceEndPoint, string requestModule, string requestMethod, Exception? innerException) {}
 
     public string RequestMethod { get; }
     public string RequestModule { get; }
   }
 
   public readonly struct KL130LightState {
     [MemberNotNullWhen(true, "IsOn")]
     [JsonPropertyName("brightness")]
     public int? Brightness { [MemberNotNullWhen(true, "IsOn")] get; [MemberNotNullWhen(true, "IsOn")] init; }
     [MemberNotNullWhen(true, "IsOn")]
     [JsonPropertyName("color_temp")]
     public int? ColorTemperature { [MemberNotNullWhen(true, "IsOn")] get; [MemberNotNullWhen(true, "IsOn")] init; }
     [MemberNotNullWhen(true, "IsOn")]
     [JsonPropertyName("hue")]
     public int? Hue { [MemberNotNullWhen(true, "IsOn")] get; [MemberNotNullWhen(true, "IsOn")] init; }
     [JsonConverter(typeof(KasaNumericalBooleanJsonConverter))]
     [JsonPropertyName("on_off")]
     public bool IsOn { get; init; }
     [MemberNotNullWhen(true, "IsOn")]
     [JsonPropertyName("mode")]
     public string? Mode { [MemberNotNullWhen(true, "IsOn")] get; [MemberNotNullWhen(true, "IsOn")] init; }
     [MemberNotNullWhen(true, "IsOn")]
     [JsonPropertyName("saturation")]
     public int? Saturation { [MemberNotNullWhen(true, "IsOn")] get; [MemberNotNullWhen(true, "IsOn")] init; }
   }
 
   public readonly struct KasaDeviceExceptionHandling {
     public static readonly KasaDeviceExceptionHandling InvalidateEndPointAndRetry; // = "{ShouldRetry=True, RetryAfter=00:00:00, ShouldReconnect=False, ShouldInvalidateEndPoint=True}"
     public static readonly KasaDeviceExceptionHandling InvalidateEndPointAndThrow; // = "{ShouldRetry=False, RetryAfter=00:00:00, ShouldReconnect=False, ShouldInvalidateEndPoint=True}"
     public static readonly KasaDeviceExceptionHandling Retry; // = "{ShouldRetry=True, RetryAfter=00:00:00, ShouldReconnect=False, ShouldInvalidateEndPoint=False}"
     public static readonly KasaDeviceExceptionHandling RetryAfterReconnect; // = "{ShouldRetry=True, RetryAfter=00:00:00, ShouldReconnect=True, ShouldInvalidateEndPoint=False}"
     public static readonly KasaDeviceExceptionHandling Throw; // = "{ShouldRetry=False, RetryAfter=00:00:00, ShouldReconnect=False, ShouldInvalidateEndPoint=False}"
 
     public static KasaDeviceExceptionHandling CreateRetry(TimeSpan retryAfter, bool shouldReconnect = false) {}
 
     public TimeSpan RetryAfter { get; init; }
     public bool ShouldInvalidateEndPoint { get; init; }
     public bool ShouldReconnect { get; init; }
     public bool ShouldRetry { get; init; }
 
     public override string ToString() {}
   }
 }
 
 namespace Smdn.TPSmartHomeDevices.Kasa.Json {
   public sealed class KasaNumericalBooleanJsonConverter : JsonConverter<bool> {
     public KasaNumericalBooleanJsonConverter() {}
 
     public override bool Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {}
     public override void Write(Utf8JsonWriter writer, bool @value, JsonSerializerOptions options) {}
   }
 }
 
 namespace Smdn.TPSmartHomeDevices.Kasa.Protocol {
   public sealed class KasaClient : IDisposable {
     public const int DefaultPort = 9999;
 
     public KasaClient(EndPoint endPoint, ILogger? logger = null) {}
 
     public EndPoint EndPoint { get; }
     public bool IsConnected { get; }
 
     public void Dispose() {}
     public ValueTask<TMethodResult> SendAsync<TMethodParameter, TMethodResult>(JsonEncodedText module, JsonEncodedText method, TMethodParameter parameter, Func<JsonElement, TMethodResult> composeResult, CancellationToken cancellationToken = default) {}
   }
 
   public static class KasaJsonSerializer {
     public const byte InitialKey = 171;
 
     public static void DecryptInPlace(Span<byte> body) {}
     public static JsonElement Deserialize(ArrayBufferWriter<byte> buffer, JsonEncodedText module, JsonEncodedText method, ILogger? logger = null) {}
     public static void EncryptInPlace(Span<byte> body) {}
     public static void Serialize<TMethodParameter>(ArrayBufferWriter<byte> buffer, JsonEncodedText module, JsonEncodedText method, TMethodParameter parameter, ILogger? logger = null) {}
   }
 
   public class KasaMessageBodyTooShortException : KasaMessageException {
     public KasaMessageBodyTooShortException(int indicatedLength, int actualLength) {}
 
     public int ActualLength { get; }
     public int IndicatedLength { get; }
   }
 
   public class KasaMessageException : SystemException {
     public KasaMessageException(string message) {}
   }
 
   public class KasaMessageHeaderTooShortException : KasaMessageException {
     public KasaMessageHeaderTooShortException(string message) {}
   }
 }
 // API list generated by Smdn.Reflection.ReverseGenerating.ListApi.MSBuild.Tasks v1.2.2.0.
 // Smdn.Reflection.ReverseGenerating.ListApi.Core v1.2.0.0 (https://github.com/smdn/Smdn.Reflection.ReverseGenerating)
diff --git a/doc/api-list/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa-net7.0.apilist.cs b/doc/api-list/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa-net7.0.apilist.cs
index 817fbf8..3576748 100644
--- a/doc/api-list/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa-net7.0.apilist.cs
+++ b/doc/api-list/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa-net7.0.apilist.cs
@@ -1,220 +1,226 @@
-// Smdn.TPSmartHomeDevices.Kasa.dll (Smdn.TPSmartHomeDevices.Kasa-1.0.0-rc1)
+// Smdn.TPSmartHomeDevices.Kasa.dll (Smdn.TPSmartHomeDevices.Kasa-1.0.0)
 //   Name: Smdn.TPSmartHomeDevices.Kasa
 //   AssemblyVersion: 1.0.0.0
-//   InformationalVersion: 1.0.0-rc1+00727d1f82dcb2b9dd9c6e586f6c54110349bf48
+//   InformationalVersion: 1.0.0+4dd7eda1e01a411bacbd6593ca050a45b3c57c37
 //   TargetFramework: .NETCoreApp,Version=v7.0
 //   Configuration: Release
 //   Referenced assemblies:
 //     Microsoft.Extensions.DependencyInjection.Abstractions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
 //     Microsoft.Extensions.Logging.Abstractions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
 //     Microsoft.Win32.Primitives, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
 //     Smdn.TPSmartHomeDevices.Primitives, Version=1.0.0.0, Culture=neutral
 //     System.Collections, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
 //     System.ComponentModel, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
 //     System.Memory, Version=7.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
 //     System.Net.NetworkInformation, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
 //     System.Net.Primitives, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
 //     System.Net.Sockets, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
 //     System.Runtime, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
 //     System.Text.Encodings.Web, Version=7.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
 //     System.Text.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
 #nullable enable annotations
 
 using System;
 using System.Buffers;
 using System.Diagnostics.CodeAnalysis;
 using System.Net;
 using System.Net.NetworkInformation;
 using System.Text.Json;
 using System.Text.Json.Serialization;
 using System.Threading;
 using System.Threading.Tasks;
+using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Logging;
 using Smdn.TPSmartHomeDevices;
 using Smdn.TPSmartHomeDevices.Kasa;
 using Smdn.TPSmartHomeDevices.Kasa.Protocol;
 
 namespace Smdn.TPSmartHomeDevices.Kasa {
   public class HS105 : KasaDevice {
     public static HS105 Create<TAddress>(TAddress deviceAddress, IServiceProvider serviceProvider) where TAddress : notnull {}
 
     public HS105(IDeviceEndPoint deviceEndPoint, IServiceProvider? serviceProvider = null) {}
     public HS105(IPAddress ipAddress, IServiceProvider? serviceProvider = null) {}
     public HS105(PhysicalAddress macAddress, IServiceProvider serviceProvider) {}
     public HS105(string host, IServiceProvider? serviceProvider = null) {}
 
     public ValueTask<bool> GetOnOffStateAsync(CancellationToken cancellationToken = default) {}
     public ValueTask SetOnOffStateAsync(bool newOnOffState, CancellationToken cancellationToken = default) {}
     public ValueTask TurnOffAsync(CancellationToken cancellationToken = default) {}
     public ValueTask TurnOnAsync(CancellationToken cancellationToken = default) {}
   }
 
   public class KL130 : KasaDevice {
     public static KL130 Create<TAddress>(TAddress deviceAddress, IServiceProvider serviceProvider) where TAddress : notnull {}
 
     public KL130(IDeviceEndPoint deviceEndPoint, IServiceProvider? serviceProvider = null) {}
     public KL130(IPAddress ipAddress, IServiceProvider? serviceProvider = null) {}
     public KL130(PhysicalAddress macAddress, IServiceProvider serviceProvider) {}
     public KL130(string host, IServiceProvider? serviceProvider = null) {}
 
     public ValueTask<KL130LightState> GetLightStateAsync(CancellationToken cancellationToken = default) {}
     public ValueTask<bool> GetOnOffStateAsync(CancellationToken cancellationToken = default) {}
     public ValueTask SetColorAsync(int hue, int saturation, int? brightness = null, TimeSpan? transitionPeriod = null, CancellationToken cancellationToken = default) {}
     public ValueTask SetColorTemperatureAsync(int colorTemperature, int? brightness = null, TimeSpan? transitionPeriod = null, CancellationToken cancellationToken = default) {}
     public ValueTask SetOnOffStateAsync(bool newOnOffState, TimeSpan? transitionPeriod = null, CancellationToken cancellationToken = default) {}
     public ValueTask TurnOffAsync(TimeSpan? transitionPeriod = null, CancellationToken cancellationToken = default) {}
     public ValueTask TurnOnAsync(TimeSpan? transitionPeriod = null, CancellationToken cancellationToken = default) {}
   }
 
   public class KasaDevice : IDisposable {
     protected readonly struct NullParameter {
     }
 
     protected static readonly JsonEncodedText MethodTextGetSysInfo; // = "get_sysinfo"
     protected static readonly JsonEncodedText ModuleTextSystem; // = "system"
 
     public static KasaDevice Create(IDeviceEndPoint deviceEndPoint, IServiceProvider? serviceProvider = null) {}
     public static KasaDevice Create(IPAddress ipAddress, IServiceProvider? serviceProvider = null) {}
     public static KasaDevice Create(PhysicalAddress macAddress, IServiceProvider serviceProvider) {}
     public static KasaDevice Create(string host, IServiceProvider? serviceProvider = null) {}
     public static KasaDevice Create<TAddress>(TAddress deviceAddress, IServiceProvider serviceProvider) where TAddress : notnull {}
 
-    protected KasaDevice(IDeviceEndPoint deviceEndPoint, IServiceProvider? serviceProvider = null) {}
-    protected KasaDevice(IPAddress ipAddress, IServiceProvider? serviceProvider = null) {}
+    protected KasaDevice(IDeviceEndPoint deviceEndPoint, IServiceProvider? serviceProvider) {}
+    protected KasaDevice(IPAddress ipAddress, IServiceProvider? serviceProvider) {}
     protected KasaDevice(PhysicalAddress macAddress, IServiceProvider serviceProvider) {}
-    protected KasaDevice(string host, IServiceProvider? serviceProvider = null) {}
+    protected KasaDevice(string host, IServiceProvider? serviceProvider) {}
 
     public bool IsConnected { get; }
     [MemberNotNullWhen(false, "deviceEndPoint")]
     protected bool IsDisposed { [MemberNotNullWhen(false, "deviceEndPoint")] get; }
 
     protected virtual void Dispose(bool disposing) {}
     public void Dispose() {}
     public ValueTask<EndPoint> ResolveEndPointAsync(CancellationToken cancellationToken = default) {}
     protected ValueTask SendRequestAsync<TMethodParameter>(JsonEncodedText module, JsonEncodedText method, TMethodParameter parameters, CancellationToken cancellationToken) {}
     protected ValueTask<TMethodResult> SendRequestAsync<TMethodParameter, TMethodResult>(JsonEncodedText module, JsonEncodedText method, TMethodParameter parameters, Func<JsonElement, TMethodResult> composeResult, CancellationToken cancellationToken) {}
     protected ValueTask<TMethodResult> SendRequestAsync<TMethodResult>(JsonEncodedText module, JsonEncodedText method, Func<JsonElement, TMethodResult> composeResult, CancellationToken cancellationToken) {}
+    public override string? ToString() {}
   }
 
   public abstract class KasaDeviceExceptionHandler {
     internal protected static readonly KasaDeviceExceptionHandler Default; // = "Smdn.TPSmartHomeDevices.Kasa.KasaDeviceDefaultExceptionHandler"
 
     protected KasaDeviceExceptionHandler() {}
 
     public abstract KasaDeviceExceptionHandling DetermineHandling(KasaDevice device, Exception exception, int attempt, ILogger? logger);
   }
 
+  public static class KasaDeviceExceptionHandlerServiceCollectionExtensions {
+    public static IServiceCollection AddKasaDeviceExceptionHandler(this IServiceCollection services, KasaDeviceExceptionHandler exceptionHandler) {}
+  }
+
   public class KasaDisconnectedException : KasaProtocolException {
     public KasaDisconnectedException(string message, EndPoint deviceEndPoint, Exception? innerException) {}
   }
 
   public class KasaErrorResponseException : KasaUnexpectedResponseException {
     public KasaErrorResponseException(EndPoint deviceEndPoint, string requestModule, string requestMethod, int rawErrorCode) {}
 
     public int RawErrorCode { get; }
   }
 
   public class KasaIncompleteResponseException : KasaUnexpectedResponseException {
     public KasaIncompleteResponseException(string message, EndPoint deviceEndPoint, string requestModule, string requestMethod, Exception? innerException) {}
   }
 
   public abstract class KasaProtocolException : InvalidOperationException {
     protected KasaProtocolException(string message, EndPoint deviceEndPoint, Exception? innerException) {}
 
     public EndPoint DeviceEndPoint { get; }
   }
 
   public class KasaUnexpectedResponseException : KasaProtocolException {
     public KasaUnexpectedResponseException(string message, EndPoint deviceEndPoint, string requestModule, string requestMethod, Exception? innerException) {}
 
     public string RequestMethod { get; }
     public string RequestModule { get; }
   }
 
   public readonly struct KL130LightState {
     [MemberNotNullWhen(true, "IsOn")]
     [JsonPropertyName("brightness")]
     public int? Brightness { [MemberNotNullWhen(true, "IsOn")] get; [MemberNotNullWhen(true, "IsOn")] init; }
     [MemberNotNullWhen(true, "IsOn")]
     [JsonPropertyName("color_temp")]
     public int? ColorTemperature { [MemberNotNullWhen(true, "IsOn")] get; [MemberNotNullWhen(true, "IsOn")] init; }
     [MemberNotNullWhen(true, "IsOn")]
     [JsonPropertyName("hue")]
     public int? Hue { [MemberNotNullWhen(true, "IsOn")] get; [MemberNotNullWhen(true, "IsOn")] init; }
     [JsonConverter(typeof(KasaNumericalBooleanJsonConverter))]
     [JsonPropertyName("on_off")]
     public bool IsOn { get; init; }
     [MemberNotNullWhen(true, "IsOn")]
     [JsonPropertyName("mode")]
     public string? Mode { [MemberNotNullWhen(true, "IsOn")] get; [MemberNotNullWhen(true, "IsOn")] init; }
     [MemberNotNullWhen(true, "IsOn")]
     [JsonPropertyName("saturation")]
     public int? Saturation { [MemberNotNullWhen(true, "IsOn")] get; [MemberNotNullWhen(true, "IsOn")] init; }
   }
 
   public readonly struct KasaDeviceExceptionHandling {
     public static readonly KasaDeviceExceptionHandling InvalidateEndPointAndRetry; // = "{ShouldRetry=True, RetryAfter=00:00:00, ShouldReconnect=False, ShouldInvalidateEndPoint=True}"
     public static readonly KasaDeviceExceptionHandling InvalidateEndPointAndThrow; // = "{ShouldRetry=False, RetryAfter=00:00:00, ShouldReconnect=False, ShouldInvalidateEndPoint=True}"
     public static readonly KasaDeviceExceptionHandling Retry; // = "{ShouldRetry=True, RetryAfter=00:00:00, ShouldReconnect=False, ShouldInvalidateEndPoint=False}"
     public static readonly KasaDeviceExceptionHandling RetryAfterReconnect; // = "{ShouldRetry=True, RetryAfter=00:00:00, ShouldReconnect=True, ShouldInvalidateEndPoint=False}"
     public static readonly KasaDeviceExceptionHandling Throw; // = "{ShouldRetry=False, RetryAfter=00:00:00, ShouldReconnect=False, ShouldInvalidateEndPoint=False}"
 
     public static KasaDeviceExceptionHandling CreateRetry(TimeSpan retryAfter, bool shouldReconnect = false) {}
 
     public TimeSpan RetryAfter { get; init; }
     public bool ShouldInvalidateEndPoint { get; init; }
     public bool ShouldReconnect { get; init; }
     public bool ShouldRetry { get; init; }
 
     public override string ToString() {}
   }
 }
 
 namespace Smdn.TPSmartHomeDevices.Kasa.Json {
   public sealed class KasaNumericalBooleanJsonConverter : JsonConverter<bool> {
     public KasaNumericalBooleanJsonConverter() {}
 
     public override bool Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {}
     public override void Write(Utf8JsonWriter writer, bool @value, JsonSerializerOptions options) {}
   }
 }
 
 namespace Smdn.TPSmartHomeDevices.Kasa.Protocol {
   public sealed class KasaClient : IDisposable {
     public const int DefaultPort = 9999;
 
     public KasaClient(EndPoint endPoint, ILogger? logger = null) {}
 
     public EndPoint EndPoint { get; }
     public bool IsConnected { get; }
 
     public void Dispose() {}
     public ValueTask<TMethodResult> SendAsync<TMethodParameter, TMethodResult>(JsonEncodedText module, JsonEncodedText method, TMethodParameter parameter, Func<JsonElement, TMethodResult> composeResult, CancellationToken cancellationToken = default) {}
   }
 
   public static class KasaJsonSerializer {
     public const byte InitialKey = 171;
 
     public static void DecryptInPlace(Span<byte> body) {}
     public static JsonElement Deserialize(ArrayBufferWriter<byte> buffer, JsonEncodedText module, JsonEncodedText method, ILogger? logger = null) {}
     public static void EncryptInPlace(Span<byte> body) {}
     public static void Serialize<TMethodParameter>(ArrayBufferWriter<byte> buffer, JsonEncodedText module, JsonEncodedText method, TMethodParameter parameter, ILogger? logger = null) {}
   }
 
   public class KasaMessageBodyTooShortException : KasaMessageException {
     public KasaMessageBodyTooShortException(int indicatedLength, int actualLength) {}
 
     public int ActualLength { get; }
     public int IndicatedLength { get; }
   }
 
   public class KasaMessageException : SystemException {
     public KasaMessageException(string message) {}
   }
 
   public class KasaMessageHeaderTooShortException : KasaMessageException {
     public KasaMessageHeaderTooShortException(string message) {}
   }
 }
 // API list generated by Smdn.Reflection.ReverseGenerating.ListApi.MSBuild.Tasks v1.2.2.0.
 // Smdn.Reflection.ReverseGenerating.ListApi.Core v1.2.0.0 (https://github.com/smdn/Smdn.Reflection.ReverseGenerating)
diff --git a/doc/api-list/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa-netstandard2.1.apilist.cs b/doc/api-list/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa-netstandard2.1.apilist.cs
index 8e9e72c..157c4be 100644
--- a/doc/api-list/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa-netstandard2.1.apilist.cs
+++ b/doc/api-list/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa-netstandard2.1.apilist.cs
@@ -1,206 +1,212 @@
-// Smdn.TPSmartHomeDevices.Kasa.dll (Smdn.TPSmartHomeDevices.Kasa-1.0.0-rc1)
+// Smdn.TPSmartHomeDevices.Kasa.dll (Smdn.TPSmartHomeDevices.Kasa-1.0.0)
 //   Name: Smdn.TPSmartHomeDevices.Kasa
 //   AssemblyVersion: 1.0.0.0
-//   InformationalVersion: 1.0.0-rc1+00727d1f82dcb2b9dd9c6e586f6c54110349bf48
+//   InformationalVersion: 1.0.0+4dd7eda1e01a411bacbd6593ca050a45b3c57c37
 //   TargetFramework: .NETStandard,Version=v2.1
 //   Configuration: Release
 //   Referenced assemblies:
 //     Microsoft.Extensions.DependencyInjection.Abstractions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
 //     Microsoft.Extensions.Logging.Abstractions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
 //     Smdn.TPSmartHomeDevices.Primitives, Version=1.0.0.0, Culture=neutral
 //     System.Text.Encodings.Web, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
 //     System.Text.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
 //     netstandard, Version=2.1.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
 #nullable enable annotations
 
 using System;
 using System.Buffers;
 using System.Net;
 using System.Net.NetworkInformation;
 using System.Text.Json;
 using System.Text.Json.Serialization;
 using System.Threading;
 using System.Threading.Tasks;
+using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Logging;
 using Smdn.TPSmartHomeDevices;
 using Smdn.TPSmartHomeDevices.Kasa;
 using Smdn.TPSmartHomeDevices.Kasa.Protocol;
 
 namespace Smdn.TPSmartHomeDevices.Kasa {
   public class HS105 : KasaDevice {
     public static HS105 Create<TAddress>(TAddress deviceAddress, IServiceProvider serviceProvider) where TAddress : notnull {}
 
     public HS105(IDeviceEndPoint deviceEndPoint, IServiceProvider? serviceProvider = null) {}
     public HS105(IPAddress ipAddress, IServiceProvider? serviceProvider = null) {}
     public HS105(PhysicalAddress macAddress, IServiceProvider serviceProvider) {}
     public HS105(string host, IServiceProvider? serviceProvider = null) {}
 
     public ValueTask<bool> GetOnOffStateAsync(CancellationToken cancellationToken = default) {}
     public ValueTask SetOnOffStateAsync(bool newOnOffState, CancellationToken cancellationToken = default) {}
     public ValueTask TurnOffAsync(CancellationToken cancellationToken = default) {}
     public ValueTask TurnOnAsync(CancellationToken cancellationToken = default) {}
   }
 
   public class KL130 : KasaDevice {
     public static KL130 Create<TAddress>(TAddress deviceAddress, IServiceProvider serviceProvider) where TAddress : notnull {}
 
     public KL130(IDeviceEndPoint deviceEndPoint, IServiceProvider? serviceProvider = null) {}
     public KL130(IPAddress ipAddress, IServiceProvider? serviceProvider = null) {}
     public KL130(PhysicalAddress macAddress, IServiceProvider serviceProvider) {}
     public KL130(string host, IServiceProvider? serviceProvider = null) {}
 
     public ValueTask<KL130LightState> GetLightStateAsync(CancellationToken cancellationToken = default) {}
     public ValueTask<bool> GetOnOffStateAsync(CancellationToken cancellationToken = default) {}
     public ValueTask SetColorAsync(int hue, int saturation, int? brightness = null, TimeSpan? transitionPeriod = null, CancellationToken cancellationToken = default) {}
     public ValueTask SetColorTemperatureAsync(int colorTemperature, int? brightness = null, TimeSpan? transitionPeriod = null, CancellationToken cancellationToken = default) {}
     public ValueTask SetOnOffStateAsync(bool newOnOffState, TimeSpan? transitionPeriod = null, CancellationToken cancellationToken = default) {}
     public ValueTask TurnOffAsync(TimeSpan? transitionPeriod = null, CancellationToken cancellationToken = default) {}
     public ValueTask TurnOnAsync(TimeSpan? transitionPeriod = null, CancellationToken cancellationToken = default) {}
   }
 
   public class KasaDevice : IDisposable {
     protected readonly struct NullParameter {
     }
 
     protected static readonly JsonEncodedText MethodTextGetSysInfo;
     protected static readonly JsonEncodedText ModuleTextSystem;
 
     public static KasaDevice Create(IDeviceEndPoint deviceEndPoint, IServiceProvider? serviceProvider = null) {}
     public static KasaDevice Create(IPAddress ipAddress, IServiceProvider? serviceProvider = null) {}
     public static KasaDevice Create(PhysicalAddress macAddress, IServiceProvider serviceProvider) {}
     public static KasaDevice Create(string host, IServiceProvider? serviceProvider = null) {}
     public static KasaDevice Create<TAddress>(TAddress deviceAddress, IServiceProvider serviceProvider) where TAddress : notnull {}
 
-    protected KasaDevice(IDeviceEndPoint deviceEndPoint, IServiceProvider? serviceProvider = null) {}
-    protected KasaDevice(IPAddress ipAddress, IServiceProvider? serviceProvider = null) {}
+    protected KasaDevice(IDeviceEndPoint deviceEndPoint, IServiceProvider? serviceProvider) {}
+    protected KasaDevice(IPAddress ipAddress, IServiceProvider? serviceProvider) {}
     protected KasaDevice(PhysicalAddress macAddress, IServiceProvider serviceProvider) {}
-    protected KasaDevice(string host, IServiceProvider? serviceProvider = null) {}
+    protected KasaDevice(string host, IServiceProvider? serviceProvider) {}
 
     public bool IsConnected { get; }
     protected bool IsDisposed { get; }
 
     protected virtual void Dispose(bool disposing) {}
     public void Dispose() {}
     public ValueTask<EndPoint> ResolveEndPointAsync(CancellationToken cancellationToken = default) {}
     protected ValueTask SendRequestAsync<TMethodParameter>(JsonEncodedText module, JsonEncodedText method, TMethodParameter parameters, CancellationToken cancellationToken) {}
     protected ValueTask<TMethodResult> SendRequestAsync<TMethodParameter, TMethodResult>(JsonEncodedText module, JsonEncodedText method, TMethodParameter parameters, Func<JsonElement, TMethodResult> composeResult, CancellationToken cancellationToken) {}
     protected ValueTask<TMethodResult> SendRequestAsync<TMethodResult>(JsonEncodedText module, JsonEncodedText method, Func<JsonElement, TMethodResult> composeResult, CancellationToken cancellationToken) {}
+    public override string? ToString() {}
   }
 
   public abstract class KasaDeviceExceptionHandler {
     internal protected static readonly KasaDeviceExceptionHandler Default; // = "Smdn.TPSmartHomeDevices.Kasa.KasaDeviceDefaultExceptionHandler"
 
     protected KasaDeviceExceptionHandler() {}
 
     public abstract KasaDeviceExceptionHandling DetermineHandling(KasaDevice device, Exception exception, int attempt, ILogger? logger);
   }
 
+  public static class KasaDeviceExceptionHandlerServiceCollectionExtensions {
+    public static IServiceCollection AddKasaDeviceExceptionHandler(this IServiceCollection services, KasaDeviceExceptionHandler exceptionHandler) {}
+  }
+
   public class KasaDisconnectedException : KasaProtocolException {
     public KasaDisconnectedException(string message, EndPoint deviceEndPoint, Exception? innerException) {}
   }
 
   public class KasaErrorResponseException : KasaUnexpectedResponseException {
     public KasaErrorResponseException(EndPoint deviceEndPoint, string requestModule, string requestMethod, int rawErrorCode) {}
 
     public int RawErrorCode { get; }
   }
 
   public class KasaIncompleteResponseException : KasaUnexpectedResponseException {
     public KasaIncompleteResponseException(string message, EndPoint deviceEndPoint, string requestModule, string requestMethod, Exception? innerException) {}
   }
 
   public abstract class KasaProtocolException : InvalidOperationException {
     protected KasaProtocolException(string message, EndPoint deviceEndPoint, Exception? innerException) {}
 
     public EndPoint DeviceEndPoint { get; }
   }
 
   public class KasaUnexpectedResponseException : KasaProtocolException {
     public KasaUnexpectedResponseException(string message, EndPoint deviceEndPoint, string requestModule, string requestMethod, Exception? innerException) {}
 
     public string RequestMethod { get; }
     public string RequestModule { get; }
   }
 
   public readonly struct KL130LightState {
     [JsonPropertyName("brightness")]
     public int? Brightness { get; init; }
     [JsonPropertyName("color_temp")]
     public int? ColorTemperature { get; init; }
     [JsonPropertyName("hue")]
     public int? Hue { get; init; }
     [JsonConverter(typeof(KasaNumericalBooleanJsonConverter))]
     [JsonPropertyName("on_off")]
     public bool IsOn { get; init; }
     [JsonPropertyName("mode")]
     public string? Mode { get; init; }
     [JsonPropertyName("saturation")]
     public int? Saturation { get; init; }
   }
 
   public readonly struct KasaDeviceExceptionHandling {
     public static readonly KasaDeviceExceptionHandling InvalidateEndPointAndRetry; // = "{ShouldRetry=True, RetryAfter=00:00:00, ShouldReconnect=False, ShouldInvalidateEndPoint=True}"
     public static readonly KasaDeviceExceptionHandling InvalidateEndPointAndThrow; // = "{ShouldRetry=False, RetryAfter=00:00:00, ShouldReconnect=False, ShouldInvalidateEndPoint=True}"
     public static readonly KasaDeviceExceptionHandling Retry; // = "{ShouldRetry=True, RetryAfter=00:00:00, ShouldReconnect=False, ShouldInvalidateEndPoint=False}"
     public static readonly KasaDeviceExceptionHandling RetryAfterReconnect; // = "{ShouldRetry=True, RetryAfter=00:00:00, ShouldReconnect=True, ShouldInvalidateEndPoint=False}"
     public static readonly KasaDeviceExceptionHandling Throw; // = "{ShouldRetry=False, RetryAfter=00:00:00, ShouldReconnect=False, ShouldInvalidateEndPoint=False}"
 
     public static KasaDeviceExceptionHandling CreateRetry(TimeSpan retryAfter, bool shouldReconnect = false) {}
 
     public TimeSpan RetryAfter { get; init; }
     public bool ShouldInvalidateEndPoint { get; init; }
     public bool ShouldReconnect { get; init; }
     public bool ShouldRetry { get; init; }
 
     public override string ToString() {}
   }
 }
 
 namespace Smdn.TPSmartHomeDevices.Kasa.Json {
   public sealed class KasaNumericalBooleanJsonConverter : JsonConverter<bool> {
     public KasaNumericalBooleanJsonConverter() {}
 
     public override bool Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {}
     [...] public override <unknown> Write(...) {}
   }
 }
 
 namespace Smdn.TPSmartHomeDevices.Kasa.Protocol {
   public sealed class KasaClient : IDisposable {
     public const int DefaultPort = 9999;
 
     public KasaClient(EndPoint endPoint, ILogger? logger = null) {}
 
     public EndPoint EndPoint { get; }
     public bool IsConnected { get; }
 
     public void Dispose() {}
     public ValueTask<TMethodResult> SendAsync<TMethodParameter, TMethodResult>(JsonEncodedText module, JsonEncodedText method, TMethodParameter parameter, Func<JsonElement, TMethodResult> composeResult, CancellationToken cancellationToken = default) {}
   }
 
   public static class KasaJsonSerializer {
     public const byte InitialKey = 171;
 
     public static void DecryptInPlace(Span<byte> body) {}
     public static JsonElement Deserialize(ArrayBufferWriter<byte> buffer, JsonEncodedText module, JsonEncodedText method, ILogger? logger = null) {}
     public static void EncryptInPlace(Span<byte> body) {}
     public static void Serialize<TMethodParameter>(ArrayBufferWriter<byte> buffer, JsonEncodedText module, JsonEncodedText method, TMethodParameter parameter, ILogger? logger = null) {}
   }
 
   public class KasaMessageBodyTooShortException : KasaMessageException {
     public KasaMessageBodyTooShortException(int indicatedLength, int actualLength) {}
 
     public int ActualLength { get; }
     public int IndicatedLength { get; }
   }
 
   public class KasaMessageException : SystemException {
     public KasaMessageException(string message) {}
   }
 
   public class KasaMessageHeaderTooShortException : KasaMessageException {
     public KasaMessageHeaderTooShortException(string message) {}
   }
 }
 // API list generated by Smdn.Reflection.ReverseGenerating.ListApi.MSBuild.Tasks v1.2.2.0.
 // Smdn.Reflection.ReverseGenerating.ListApi.Core v1.2.0.0 (https://github.com/smdn/Smdn.Reflection.ReverseGenerating)

Full changes

Full changes in this release:
diff --git a/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa.Protocol/KasaClient.cs b/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa.Protocol/KasaClient.cs
index ca77558..5079b04 100644
--- a/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa.Protocol/KasaClient.cs
+++ b/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa.Protocol/KasaClient.cs
@@ -146,7 +146,10 @@ public sealed partial class KasaClient : IDisposable {
   )
 #pragma warning restore SA1112
   {
-    var s = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
+    var addressFamily = endPoint.AddressFamily == AddressFamily.Unspecified
+      ? Socket.OSSupportsIPv6 ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork
+      : endPoint.AddressFamily;
+    var s = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp);
 
     try {
       logger?.LogDebug("Connecting");
@@ -279,6 +282,8 @@ public sealed partial class KasaClient : IDisposable {
       /*
        * decrypt and parse
        */
+      cancellationToken.ThrowIfCancellationRequested();
+
       JsonElement result = default;
 
       try {
diff --git a/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa.csproj b/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa.csproj
index d4226bb..20a83cd 100644
--- a/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa.csproj
+++ b/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa.csproj
@@ -7,7 +7,7 @@ SPDX-License-Identifier: MIT
     <TargetFrameworks>netstandard2.1;net6.0</TargetFrameworks>
     <TargetFrameworks Condition="$([MSBuild]::VersionGreaterThanOrEquals('$(NETCoreSdkVersion)', '7.0.0'))">net7.0;$(TargetFrameworks)</TargetFrameworks>
     <VersionPrefix>1.0.0</VersionPrefix>
-    <VersionSuffix>rc1</VersionSuffix>
+    <VersionSuffix></VersionSuffix>
     <!-- <PackageValidationBaselineVersion>1.0.0</PackageValidationBaselineVersion> -->
     <Nullable>enable</Nullable>
     <DefineConstants
@@ -23,14 +23,13 @@ SPDX-License-Identifier: MIT
   </PropertyGroup>
 
   <PropertyGroup Label="assembly attributes">
-    <Description>
-<![CDATA[Provides APIs for operating Kasa devices, the TP-Link smart home devices.
-]]></Description>
+    <Description>Provides APIs for operating Kasa devices, the TP-Link smart home devices.</Description>
     <CopyrightYear>2023</CopyrightYear>
   </PropertyGroup>
 
   <PropertyGroup Label="package properties">
     <PackageTags>tplink-kasa,kasa,HS105,KL130,$(PackageCommonTags)</PackageTags>
+    <GenerateNupkgReadmeFileDependsOnTargets>$(GenerateNupkgReadmeFileDependsOnTargets);GenerateReadmeFileContent</GenerateNupkgReadmeFileDependsOnTargets>
   </PropertyGroup>
 
   <PropertyGroup Label="StyleCop code analysis">
@@ -43,7 +42,7 @@ SPDX-License-Identifier: MIT
 
   <ItemGroup>
     <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" />
-    <ProjectOrPackageReference ReferencePackageVersion="[1.0.0-*,2.0.0)" Include="..\Smdn.TPSmartHomeDevices.Primitives\Smdn.TPSmartHomeDevices.Primitives.csproj" />
+    <ProjectOrPackageReference ReferencePackageVersion="[1.0.0,2.0.0)" Include="..\Smdn.TPSmartHomeDevices.Primitives\Smdn.TPSmartHomeDevices.Primitives.csproj" />
   </ItemGroup>
 
   <ItemGroup>
@@ -63,4 +62,41 @@ SPDX-License-Identifier: MIT
     />
   </ItemGroup>
 
+  <Target Name="GenerateReadmeFileContent" DependsOnTargets="ReadReadmeFileNoticeSectionContent">
+    <PropertyGroup>
+      <PackageReadmeFileContent><![CDATA[# $(PackageId) $(PackageVersion)
+`$(PackageId)` is a library that provides APIs for operating Kasa, the TP-Link smart home devices.
+This library performs operations by communicating directly with Kasa devices in the same network.
+
+This library also provides following features:
+
+- Automatic connection management, including reconnection.
+- Built-in/customizable error handling for typical errors and retries (like device busy, request timeout).
+- Using MAC address and following IP address change in DHCP networks (requires [Smdn.TPSmartHomeDevices.MacAddressEndPoint](https://www.nuget.org/packages/Smdn.TPSmartHomeDevices.MacAddressEndPoint/)).
+- `async` operation and cancellation.
+
+## Getting started
+First, add package `$(PackageId)` to the project file.
+
+```
+dotnet add package $(PackageId)
+```
+
+To operate the Kasa device, write code like the following. Replace the Kasa device's IP address with yours.
+
+```cs
+$([System.IO.File]::ReadAllText('$(MSBuildThisFileDirectory)..\..\examples\$(PackageId)\GettingStarted\Program.cs').TrimEnd())
+```
+
+More examples can be found on the [GitHub repository]($(RepositoryUrl)/tree/main/examples/$(PackageId)/), including examples of using other Kasa devices and their functionalities, and examples of using library features.
+
+## Contributing
+This project welcomes contributions, feedbacks and suggestions. You can contribute to this project by submitting [Issues]($(RepositoryUrl)/issues/new/choose) or [Pull Requests]($(RepositoryUrl)/pulls/) on the [GitHub repository]($(RepositoryUrl)).
+
+## Notice
+$(ReadmeFileNoticeSectionContent)
+]]></PackageReadmeFileContent>
+    </PropertyGroup>
+  </Target>
+
 </Project>
diff --git a/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa/KasaDevice.cs b/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa/KasaDevice.cs
index 2cb76c1..80715f2 100644
--- a/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa/KasaDevice.cs
+++ b/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa/KasaDevice.cs
@@ -94,7 +94,7 @@ public partial class KasaDevice : IDisposable {
   /// </param>
   protected KasaDevice(
     string host,
-    IServiceProvider? serviceProvider = null
+    IServiceProvider? serviceProvider
   )
     : this(
       deviceEndPoint: DeviceEndPoint.Create(host),
@@ -114,7 +114,7 @@ public partial class KasaDevice : IDisposable {
   /// </param>
   protected KasaDevice(
     IPAddress ipAddress,
-    IServiceProvider? serviceProvider = null
+    IServiceProvider? serviceProvider
   )
     : this(
       deviceEndPoint: DeviceEndPoint.Create(ipAddress),
@@ -163,7 +163,7 @@ public partial class KasaDevice : IDisposable {
   /// </exception>
   protected KasaDevice(
     IDeviceEndPoint deviceEndPoint,
-    IServiceProvider? serviceProvider = null
+    IServiceProvider? serviceProvider
   )
   {
     this.deviceEndPoint = deviceEndPoint ?? throw new ArgumentNullException(nameof(deviceEndPoint));
@@ -444,4 +444,9 @@ public partial class KasaDevice : IDisposable {
     throw new NotImplementedException("unreachable");
 #endif
   }
+
+  /// <summary>Returns a string that represents the current object.</summary>
+  /// <returns>A string that represents the device type name and end point.</returns>
+  public override string? ToString()
+    => $"{GetType().Name} ({deviceEndPoint?.ToString() ?? "disposed"})";
 }
diff --git a/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa/KasaDeviceExceptionHandlerServiceCollectionExtensions.cs b/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa/KasaDeviceExceptionHandlerServiceCollectionExtensions.cs
new file mode 100644
index 0000000..0ac7c9d
--- /dev/null
+++ b/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa/KasaDeviceExceptionHandlerServiceCollectionExtensions.cs
@@ -0,0 +1,31 @@
+// SPDX-FileCopyrightText: 2023 smdn <smdn@smdn.jp>
+// SPDX-License-Identifier: MIT
+using System;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+
+namespace Smdn.TPSmartHomeDevices.Kasa;
+
+public static class KasaDeviceExceptionHandlerServiceCollectionExtensions {
+  /// <summary>
+  /// Adds <see cref="KasaDeviceExceptionHandler"/> to <see cref="IServiceCollection"/>.
+  /// </summary>
+  /// <param name="services">The <see cref="IServiceCollection"/> to add services to.</param>
+  /// <param name="exceptionHandler">A <see cref="KasaDeviceExceptionHandler"/> used for exception handling in <see cref="KasaDevice"/>.</param>
+  public static IServiceCollection AddKasaDeviceExceptionHandler(
+    this IServiceCollection services,
+    KasaDeviceExceptionHandler exceptionHandler
+  )
+  {
+    if (services is null)
+      throw new ArgumentNullException(nameof(services));
+    if (exceptionHandler is null)
+      throw new ArgumentNullException(nameof(exceptionHandler));
+
+    services.TryAdd(
+      ServiceDescriptor.Singleton(typeof(KasaDeviceExceptionHandler), exceptionHandler)
+    );
+
+    return services;
+  }
+}
diff --git a/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa/KasaDeviceExceptionHandling.cs b/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa/KasaDeviceExceptionHandling.cs
index 480fe51..75c4c86 100644
--- a/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa/KasaDeviceExceptionHandling.cs
+++ b/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa/KasaDeviceExceptionHandling.cs
@@ -40,8 +40,7 @@ public readonly struct KasaDeviceExceptionHandling {
   /// </summary>
   /// <param name="retryAfter">The <see cref="TimeSpan"/> that specifies the amount of time to wait before retry.</param>
   /// <param name="shouldReconnect">
-  /// The <see cref="bool"/> value that specifies whether the
-  /// <see cref="IDynamicDeviceEndPoint.Invalidate"/> should be invoked before retry or not.
+  /// The <see cref="bool"/> value that specifies whether the connection should be re-connected before retry or not.
   /// </param>
   public static KasaDeviceExceptionHandling CreateRetry(
     TimeSpan retryAfter,
diff --git a/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa/KasaDisconnectedException.cs b/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa/KasaDisconnectedException.cs
index ebd8161..eaeb815 100644
--- a/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa/KasaDisconnectedException.cs
+++ b/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa/KasaDisconnectedException.cs
@@ -5,6 +5,9 @@ using System.Net;
 
 namespace Smdn.TPSmartHomeDevices.Kasa;
 
+/// <summary>
+/// The exception that is thrown when the Kasa device disconnects the connection.
+/// </summary>
 public class KasaDisconnectedException : KasaProtocolException {
   public KasaDisconnectedException(
     string message,
diff --git a/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa/KasaErrorResponseException.cs b/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa/KasaErrorResponseException.cs
index a805177..2535a1c 100644
--- a/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa/KasaErrorResponseException.cs
+++ b/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa/KasaErrorResponseException.cs
@@ -4,7 +4,13 @@ using System.Net;
 
 namespace Smdn.TPSmartHomeDevices.Kasa;
 
+/// <summary>
+/// The exception that is thrown when the Kasa device responds a response with an error code.
+/// </summary>
 public class KasaErrorResponseException : KasaUnexpectedResponseException {
+  /// <summary>
+  /// Gets the <c>error_code</c> of the response that caused the exception.
+  /// </summary>
   public int RawErrorCode { get; }
 
   public KasaErrorResponseException(
diff --git a/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa/KasaIncompleteResponseException.cs b/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa/KasaIncompleteResponseException.cs
index 954aa05..8336dfc 100644
--- a/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa/KasaIncompleteResponseException.cs
+++ b/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa/KasaIncompleteResponseException.cs
@@ -5,6 +5,13 @@ using System.Net;
 
 namespace Smdn.TPSmartHomeDevices.Kasa;
 
+/// <summary>
+/// The exception that is thrown when the Kasa device responds an incomplete response.
+/// </summary>
+/// <remarks>
+/// The Kasa devices indicates the its length at the beginning of response, but may actually send a response less than that length and stop responding.
+/// <see cref="KasaIncompleteResponseException"/> is thrown when such a response is received.
+/// </remarks>
 public class KasaIncompleteResponseException : KasaUnexpectedResponseException {
   public KasaIncompleteResponseException(
     string message,
diff --git a/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa/KasaProtocolException.cs b/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa/KasaProtocolException.cs
index a0e4b91..21ef398 100644
--- a/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa/KasaProtocolException.cs
+++ b/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa/KasaProtocolException.cs
@@ -5,7 +5,13 @@ using System.Net;
 
 namespace Smdn.TPSmartHomeDevices.Kasa;
 
+/// <summary>
+/// The exception that is thrown when the communication with the Kasa device encounters an unrecoverable condition.
+/// </summary>
 public abstract class KasaProtocolException : InvalidOperationException {
+  /// <summary>
+  /// Gets the <see cref="EndPoint"/> of the Kasa device that caused the exception.
+  /// </summary>
   public EndPoint DeviceEndPoint { get; }
 
   protected KasaProtocolException(
diff --git a/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa/KasaUnexpectedResponseException.cs b/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa/KasaUnexpectedResponseException.cs
index c3d54f4..3ff8b1f 100644
--- a/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa/KasaUnexpectedResponseException.cs
+++ b/src/Smdn.TPSmartHomeDevices.Kasa/Smdn.TPSmartHomeDevices.Kasa/KasaUnexpectedResponseException.cs
@@ -5,8 +5,18 @@ using System.Net;
 
 namespace Smdn.TPSmartHomeDevices.Kasa;
 
+/// <summary>
+/// The exception that is thrown when the Kasa device responds a unexpected response.
+/// </summary>
 public class KasaUnexpectedResponseException : KasaProtocolException {
+  /// <summary>
+  /// Gets the <c>module</c> of the request that caused the exception.
+  /// </summary>
   public string RequestModule { get; }
+
+  /// <summary>
+  /// Gets the <c>method</c> of the request that caused the exception.
+  /// </summary>
   public string RequestMethod { get; }
 
   public KasaUnexpectedResponseException(

Notes

Full Changelog: releases/Smdn.TPSmartHomeDevices.Kasa-1.0.0-rc1...releases/Smdn.TPSmartHomeDevices.Kasa-1.0.0