Smdn.TPSmartHomeDevices.Tapo 2.0.0

The ID prefix of this package has been reserved for one of the owners of this package by NuGet.org. Prefix Reserved
dotnet add package Smdn.TPSmartHomeDevices.Tapo --version 2.0.0
NuGet\Install-Package Smdn.TPSmartHomeDevices.Tapo -Version 2.0.0
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Smdn.TPSmartHomeDevices.Tapo" Version="2.0.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Smdn.TPSmartHomeDevices.Tapo --version 2.0.0
#r "nuget: Smdn.TPSmartHomeDevices.Tapo, 2.0.0"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Smdn.TPSmartHomeDevices.Tapo as a Cake Addin
#addin nuget:?package=Smdn.TPSmartHomeDevices.Tapo&version=2.0.0

// Install Smdn.TPSmartHomeDevices.Tapo as a Cake Tool
#tool nuget:?package=Smdn.TPSmartHomeDevices.Tapo&version=2.0.0

Smdn.TPSmartHomeDevices.Tapo 2.0.0

Smdn.TPSmartHomeDevices.Tapo is a library that provides APIs for operating Tapo, the TP-Link smart home devices. This library performs operations by communicating directly with Tapo devices in the same network. Remote operation via the Internet is not supported.

This library also provides following features:

  • Support for both older protocol (securePassthrough) and newer protocol (KLAP). The protocol selection is automatically performed according to the firmware of the target device.
  • Automatic connection/authentication/session management, including reconnection and re-authentication.
  • Built-in/customizable error handling for typical errors and retries (like device busy, session expired, request timeout).
  • Using MAC address and following IP address change in DHCP networks (requires Smdn.TPSmartHomeDevices.MacAddressEndPoint).
  • async operation and cancellation.

Getting started

First, add package Smdn.TPSmartHomeDevices.Tapo to the project file.

dotnet add package Smdn.TPSmartHomeDevices.Tapo

To operate the Tapo device, write code like the following. Replace the Tapo device's IP address and Tapo account information with yours.

using Smdn.TPSmartHomeDevices.Tapo;

// Creates device controller for Tapo L530 multicolor light bulb.
using var bulb = new L530(
  "192.0.2.1",      // IP address currently assigned to L530
  "user@mail.test", // E-mail address for your Tapo account
  "password"        // Password for your Tapo account
);

// Turns on the bulb, and set the color temperature and brightness.
await bulb.SetColorTemperatureAsync(colorTemperature: 5500, brightness: 80);

// Turns off the bulb
await bulb.TurnOffAsync();

More examples can be found on the GitHub repository, including examples of using other Tapo 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 or Pull Requests on the GitHub repository.

Notice

License

This project is licensed under the GNU GPL version 3 or later.

This project includes source code licensed under MIT or GPLv3 as described below and produces artifacts licensed in accordance therewith.

Smdn.TPSmartHomeDevices.Tapo (GPLv3)

The some source files in the directory under the src/Smdn.TPSmartHomeDevices.Tapo/ include codes that has been ported from codes which licensed under the GPLv3, and are licensed under the GNU GPL version 3 or later.

Therefore, artifacts from this directory, including NuGet package Smdn.TPSmartHomeDevices.Tapo, are released under the GNU GPL version 3 or later.

For the license of individual files, refer to SPDX-License-Identifier at the top of each file header.

Smdn.TPSmartHomeDevices.Kasa, Smdn.TPSmartHomeDevices.MacAddressEndPoint, Smdn.TPSmartHomeDevices.Primitives (MIT)

The source files and generated artifacts from the directory under the src/, excluding Smdn.TPSmartHomeDevices.Tapo, are licensed and released under the terms of the MIT License.

Disclaimer

(An English translation for the reference follows the text written in Japanese.)

本プロジェクトは、TP-Linkとは無関係の非公式なものです。

This is an unofficial project that has no affiliation with TP-Link.

本プロジェクトが提供するソフトウェアは、デバイスの設定の取得・変更等、製品仕様の範囲内での操作のみを行うものであり、ファームウェアの改変・修正および製品の改造や製品仕様の変更を引き起こさないものの、製品使用上の許諾事項に抵触する可能性は否定できないため、使用の際はその点にご留意ください。

The software provided by this project is intended only for operations within the scope of the product specifications, such as acquiring and changing device settings, and while it does not cause altering the product itself, product's firmware or operating specifications. Nevertheless, please note that the possibility of violating terms of use of the product cannot be dismissed when using the software provided by this project.

TapoKasa、および各製品名の著作権はTP-Linkに帰属します。

Tapo, Kasa and all respective product names are copyright of TP-Link.

Credit

This project incorporates implementations partially ported from the following projects. See also ThirdPartyNotices.md for detail.

API List

List of APIs exposed by assembly Smdn.TPSmartHomeDevices.Tapo-2.0.0 (net8.0)

// Smdn.TPSmartHomeDevices.Tapo.dll (Smdn.TPSmartHomeDevices.Tapo-2.0.0)
//   Name: Smdn.TPSmartHomeDevices.Tapo
//   AssemblyVersion: 2.0.0.0
//   InformationalVersion: 2.0.0+b94237e3ade205b0c2874616f6f9c9259586dcbd
//   TargetFramework: .NETCoreApp,Version=v8.0
//   Configuration: Release
//   Referenced assemblies:
//     Microsoft.Extensions.DependencyInjection.Abstractions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
//     Microsoft.Extensions.Http, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
//     Microsoft.Extensions.Logging.Abstractions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
//     Smdn.Fundamental.PrintableEncoding.Hexadecimal, Version=3.0.1.0, Culture=neutral
//     Smdn.TPSmartHomeDevices.Primitives, Version=1.1.0.0, Culture=neutral
//     System.Collections, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
//     System.ComponentModel, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
//     System.Linq, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
//     System.Memory, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
//     System.Net.Http, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
//     System.Net.Http.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
//     System.Net.NetworkInformation, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
//     System.Net.Primitives, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
//     System.Runtime, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
//     System.Security.Cryptography, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
//     System.Text.Encodings.Web, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
//     System.Text.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
#nullable enable annotations

using System;
using System.Buffers;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Net;
using System.Net.Http;
using System.Net.NetworkInformation;
using System.Security.Cryptography;
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.Tapo;
using Smdn.TPSmartHomeDevices.Tapo.Credentials;
using Smdn.TPSmartHomeDevices.Tapo.Json;
using Smdn.TPSmartHomeDevices.Tapo.Protocol;

namespace Smdn.TPSmartHomeDevices.Tapo {
  public class L530 :
    TapoDevice,
    IMulticolorSmartLight
  {
    public static L530 Create<TAddress>(TAddress deviceAddress, IServiceProvider serviceProvider, ITapoCredentialProvider? credential = null) where TAddress : notnull {}

    public L530(IDeviceEndPoint deviceEndPoint, ITapoCredentialProvider? credential = null, IServiceProvider? serviceProvider = null) {}
    public L530(IPAddress ipAddress, IServiceProvider serviceProvider) {}
    public L530(IPAddress ipAddress, string email, string password, IServiceProvider? serviceProvider = null) {}
    public L530(PhysicalAddress macAddress, IServiceProvider serviceProvider) {}
    public L530(PhysicalAddress macAddress, string email, string password, IServiceProvider serviceProvider) {}
    public L530(string host, IServiceProvider serviceProvider) {}
    public L530(string host, string email, string password, IServiceProvider? serviceProvider = null) {}

    public ValueTask SetBrightnessAsync(int brightness, CancellationToken cancellationToken = default) {}
    public ValueTask SetColorAsync(int hue, int saturation, int? brightness = null, CancellationToken cancellationToken = default) {}
    public ValueTask SetColorHueAsync(int hue, int? brightness = null, CancellationToken cancellationToken = default) {}
    public ValueTask SetColorSaturationAsync(int saturation, int? brightness = null, CancellationToken cancellationToken = default) {}
    public ValueTask SetColorTemperatureAsync(int colorTemperature, int? brightness = null, CancellationToken cancellationToken = default) {}
    ValueTask IMulticolorSmartLight.SetColorAsync(int hue, int saturation, int? brightness, TimeSpan transitionPeriod, CancellationToken cancellationToken) {}
    ValueTask IMulticolorSmartLight.SetColorTemperatureAsync(int colorTemperature, int? brightness, TimeSpan transitionPeriod, CancellationToken cancellationToken) {}
    ValueTask ISmartLight.SetBrightnessAsync(int brightness, TimeSpan transitionPeriod, CancellationToken cancellationToken) {}
  }

  public class L900 :
    TapoDevice,
    IMulticolorSmartLight
  {
    public static L900 Create<TAddress>(TAddress deviceAddress, IServiceProvider serviceProvider, ITapoCredentialProvider? credential = null) where TAddress : notnull {}

    public L900(IDeviceEndPoint deviceEndPoint, ITapoCredentialProvider? credential = null, IServiceProvider? serviceProvider = null) {}
    public L900(IPAddress ipAddress, IServiceProvider serviceProvider) {}
    public L900(IPAddress ipAddress, string email, string password, IServiceProvider? serviceProvider = null) {}
    public L900(PhysicalAddress macAddress, IServiceProvider serviceProvider) {}
    public L900(PhysicalAddress macAddress, string email, string password, IServiceProvider serviceProvider) {}
    public L900(string host, IServiceProvider serviceProvider) {}
    public L900(string host, string email, string password, IServiceProvider? serviceProvider = null) {}

    public ValueTask SetBrightnessAsync(int brightness, CancellationToken cancellationToken = default) {}
    public ValueTask SetColorAsync(int hue, int saturation, int? brightness = null, CancellationToken cancellationToken = default) {}
    public ValueTask SetColorHueAsync(int hue, int? brightness, CancellationToken cancellationToken = default) {}
    public ValueTask SetColorSaturationAsync(int saturation, int? brightness = null, CancellationToken cancellationToken = default) {}
    public ValueTask SetColorTemperatureAsync(int colorTemperature, int? brightness = null, CancellationToken cancellationToken = default) {}
    ValueTask IMulticolorSmartLight.SetColorAsync(int hue, int saturation, int? brightness, TimeSpan transitionPeriod, CancellationToken cancellationToken) {}
    ValueTask IMulticolorSmartLight.SetColorTemperatureAsync(int colorTemperature, int? brightness, TimeSpan transitionPeriod, CancellationToken cancellationToken) {}
    ValueTask ISmartLight.SetBrightnessAsync(int brightness, TimeSpan transitionPeriod, CancellationToken cancellationToken) {}
  }

  public class P105 : TapoDevice {
    public static P105 Create<TAddress>(TAddress deviceAddress, IServiceProvider serviceProvider, ITapoCredentialProvider? credential = null) where TAddress : notnull {}

    public P105(IDeviceEndPoint deviceEndPoint, ITapoCredentialProvider? credential = null, IServiceProvider? serviceProvider = null) {}
    public P105(IPAddress ipAddress, IServiceProvider serviceProvider) {}
    public P105(IPAddress ipAddress, string email, string password, IServiceProvider? serviceProvider = null) {}
    public P105(PhysicalAddress macAddress, IServiceProvider serviceProvider) {}
    public P105(PhysicalAddress macAddress, string email, string password, IServiceProvider serviceProvider) {}
    public P105(string host, IServiceProvider serviceProvider) {}
    public P105(string host, string email, string password, IServiceProvider? serviceProvider = null) {}
  }

  public class P110M : TapoDevice {
    public static P110M Create<TAddress>(TAddress deviceAddress, IServiceProvider serviceProvider, ITapoCredentialProvider? credential = null) where TAddress : notnull {}

    public P110M(IDeviceEndPoint deviceEndPoint, ITapoCredentialProvider? credential = null, IServiceProvider? serviceProvider = null) {}
    public P110M(IPAddress ipAddress, IServiceProvider serviceProvider) {}
    public P110M(IPAddress ipAddress, string email, string password, IServiceProvider? serviceProvider = null) {}
    public P110M(PhysicalAddress macAddress, IServiceProvider serviceProvider) {}
    public P110M(PhysicalAddress macAddress, string email, string password, IServiceProvider serviceProvider) {}
    public P110M(string host, IServiceProvider serviceProvider) {}
    public P110M(string host, string email, string password, IServiceProvider? serviceProvider = null) {}

    public virtual ValueTask<decimal?> GetCurrentPowerConsumptionAsync(CancellationToken cancellationToken = default) {}
    public virtual ValueTask<TapoPlugMonitoringData> GetMonitoringDataAsync(CancellationToken cancellationToken = default) {}
  }

  public class TapoAuthenticationException : TapoProtocolException {
    public TapoAuthenticationException(string message, Uri endPoint, Exception? innerException = null) {}
  }

  public static class TapoCredentailProviderServiceCollectionExtensions {
    public static IServiceCollection AddTapoBase64EncodedCredential(this IServiceCollection services, string base64UserNameSHA1Digest, string base64Password) {}
    public static IServiceCollection AddTapoBase64EncodedKlapCredentialFromEnvironmentVariable(this IServiceCollection services, string envVarBase64KlapLocalAuthHash) {}
    public static IServiceCollection AddTapoCredential(this IServiceCollection services, string email, string password) {}
    public static IServiceCollection AddTapoCredentialFromEnvironmentVariable(this IServiceCollection services, string envVarUsername, string envVarPassword) {}
    public static IServiceCollection AddTapoCredentialProvider(this IServiceCollection services, ITapoCredentialProvider credentialProvider) {}
  }

  public class TapoDevice :
    IDisposable,
    ISmartDevice,
    ITapoCredentialIdentity
  {
    public static TapoDevice Create(IDeviceEndPoint deviceEndPoint, ITapoCredentialProvider? credential = null, IServiceProvider? serviceProvider = null) {}
    public static TapoDevice Create(IPAddress ipAddress, IServiceProvider serviceProvider) {}
    public static TapoDevice Create(IPAddress ipAddress, string email, string password, IServiceProvider? serviceProvider = null) {}
    public static TapoDevice Create(PhysicalAddress macAddress, IServiceProvider serviceProvider) {}
    public static TapoDevice Create(PhysicalAddress macAddress, string email, string password, IServiceProvider serviceProvider) {}
    public static TapoDevice Create(string host, IServiceProvider serviceProvider) {}
    public static TapoDevice Create(string host, string email, string password, IServiceProvider? serviceProvider = null) {}
    public static TapoDevice Create<TAddress>(TAddress deviceAddress, IServiceProvider serviceProvider, ITapoCredentialProvider? credential = null) where TAddress : notnull {}

    protected TapoDevice(IDeviceEndPoint deviceEndPoint, ITapoCredentialProvider? credential, IServiceProvider? serviceProvider) {}
    protected TapoDevice(IDeviceEndPoint deviceEndPoint, ITapoCredentialProvider? credential, TapoDeviceExceptionHandler? exceptionHandler, IServiceProvider? serviceProvider) {}
    protected TapoDevice(IPAddress ipAddress, IServiceProvider serviceProvider) {}
    protected TapoDevice(IPAddress ipAddress, string email, string password, IServiceProvider? serviceProvider) {}
    protected TapoDevice(PhysicalAddress macAddress, IServiceProvider serviceProvider) {}
    protected TapoDevice(PhysicalAddress macAddress, string email, string password, IServiceProvider serviceProvider) {}
    protected TapoDevice(string host, IServiceProvider serviceProvider) {}
    protected TapoDevice(string host, string email, string password, IServiceProvider? serviceProvider) {}

    public IDeviceEndPoint EndPoint { get; }
    [MemberNotNullWhen(false, "deviceEndPoint")]
    protected bool IsDisposed { [MemberNotNullWhen(false, "deviceEndPoint")] get; }
    public TapoSession? Session { get; }
    public string TerminalUuidString { get; }
    public TimeSpan? Timeout { get; set; }

    protected virtual void Dispose(bool disposing) {}
    public void Dispose() {}
    protected ValueTask EnsureSessionEstablishedAsync(CancellationToken cancellationToken = default) {}
    public virtual ValueTask<TapoDeviceEnergyUsage?> GetCumulativeEnergyUsageAsync(CancellationToken cancellationToken = default) {}
    public ValueTask<TDeviceInfo> GetDeviceInfoAsync<TDeviceInfo>(CancellationToken cancellationToken = default) {}
    public ValueTask<TResult> GetDeviceInfoAsync<TDeviceInfo, TResult>(Func<TDeviceInfo, TResult> composeResult, CancellationToken cancellationToken = default) {}
    public ValueTask<TapoDeviceInfo> GetDeviceInfoAsync(CancellationToken cancellationToken = default) {}
    public virtual ValueTask<(TapoDeviceOperatingTime? TotalOperatingTime, TapoDeviceEnergyUsage? CumulativeEnergyUsage)> GetDeviceUsageAsync(CancellationToken cancellationToken = default) {}
    public ValueTask<bool> GetOnOffStateAsync(CancellationToken cancellationToken = default) {}
    public virtual ValueTask<TapoDeviceOperatingTime?> GetTotalOperatingTimeAsync(CancellationToken cancellationToken = default) {}
    public ValueTask<EndPoint> ResolveEndPointAsync(CancellationToken cancellationToken = default) {}
    protected ValueTask SendRequestAsync<TRequest, TResponse>(TRequest request, CancellationToken cancellationToken = default) where TRequest : notnull, ITapoPassThroughRequest where TResponse : ITapoPassThroughResponse {}
    protected ValueTask<TResult> SendRequestAsync<TRequest, TResponse, TResult>(TRequest request, Func<TResponse, TResult> composeResult, CancellationToken cancellationToken = default) where TRequest : notnull, ITapoPassThroughRequest where TResponse : ITapoPassThroughResponse {}
    public ValueTask SetDeviceInfoAsync<TDeviceInfo>(TDeviceInfo deviceInfo, CancellationToken cancellationToken = default) {}
    public ValueTask SetOnOffStateAsync(bool newOnOffState, CancellationToken cancellationToken = default) {}
    async ValueTask<IDeviceInfo> ISmartDevice.GetDeviceInfoAsync(CancellationToken cancellationToken) {}
    public override string? ToString() {}
    public ValueTask TurnOffAsync(CancellationToken cancellationToken = default) {}
    public ValueTask TurnOnAsync(CancellationToken cancellationToken = default) {}
  }

  public abstract class TapoDeviceExceptionHandler {
    internal protected static readonly TapoDeviceExceptionHandler Default; // = "Smdn.TPSmartHomeDevices.Tapo.TapoDeviceDefaultExceptionHandler"

    protected TapoDeviceExceptionHandler() {}

    public abstract TapoDeviceExceptionHandling DetermineHandling(TapoDevice device, Exception exception, int attempt, ILogger? logger);
  }

  public static class TapoDeviceExceptionHandlerServiceCollectionExtensions {
    public static IServiceCollection AddTapoDeviceExceptionHandler(this IServiceCollection services, TapoDeviceExceptionHandler exceptionHandler) {}
  }

  public class TapoDeviceInfo : IDeviceInfo {
    public TapoDeviceInfo() {}

    [JsonPropertyName("avatar")]
    public string? Avatar { get; init; }
    [JsonConverter(typeof(Base16ByteArrayJsonConverter))]
    [JsonPropertyName("fw_id")]
    public byte[]? FirmwareId { get; init; }
    [JsonPropertyName("fw_ver")]
    public string? FirmwareVersion { get; init; }
    [JsonConverter(typeof(GeolocationInDecimalDegreesJsonConverter))]
    [JsonPropertyName("latitude")]
    public decimal? GeolocationLatitude { get; init; }
    [JsonConverter(typeof(GeolocationInDecimalDegreesJsonConverter))]
    [JsonPropertyName("longitude")]
    public decimal? GeolocationLongitude { get; init; }
    [JsonConverter(typeof(Base16ByteArrayJsonConverter))]
    [JsonPropertyName("hw_id")]
    public byte[]? HardwareId { get; init; }
    [JsonPropertyName("specs")]
    public string? HardwareSpecifications { get; init; }
    [JsonPropertyName("hw_ver")]
    public string? HardwareVersion { get; init; }
    [JsonPropertyName("has_set_location_info")]
    public bool HasGeolocationInfoSet { get; init; }
    [JsonConverter(typeof(TapoIPAddressJsonConverter))]
    [JsonPropertyName("ip")]
    public IPAddress? IPAddress { get; init; }
    [JsonConverter(typeof(Base16ByteArrayJsonConverter))]
    [JsonPropertyName("device_id")]
    public byte[]? Id { get; init; }
    [JsonPropertyName("device_on")]
    public bool IsOn { get; init; }
    [JsonPropertyName("overheated")]
    public bool IsOverheated { get; init; }
    [JsonPropertyName("lang")]
    public string? Language { get; init; }
    [JsonConverter(typeof(MacAddressJsonConverter))]
    [JsonPropertyName("mac")]
    public PhysicalAddress? MacAddress { get; init; }
    [JsonPropertyName("model")]
    public string? ModelName { get; init; }
    [JsonPropertyName("rssi")]
    public decimal? NetworkRssi { get; init; }
    [JsonPropertyName("signal_level")]
    public int? NetworkSignalLevel { get; init; }
    [JsonConverter(typeof(TapoBase64StringJsonConverter))]
    [JsonPropertyName("ssid")]
    public string? NetworkSsid { get; init; }
    [JsonConverter(typeof(TapoBase64StringJsonConverter))]
    [JsonPropertyName("nickname")]
    public string? NickName { get; init; }
    [JsonConverter(typeof(Base16ByteArrayJsonConverter))]
    [JsonPropertyName("oem_id")]
    public byte[]? OemId { get; init; }
    [JsonConverter(typeof(TimeSpanInSecondsJsonConverter))]
    [JsonPropertyName("on_time")]
    public TimeSpan? OnTimeDuration { get; init; }
    ReadOnlySpan<byte> IDeviceInfo.Id { get; }
    [JsonIgnore]
    public DateTimeOffset TimeStamp { get; }
    [JsonConverter(typeof(TimeSpanInMinutesJsonConverter))]
    [JsonPropertyName("time_diff")]
    public TimeSpan? TimeZoneOffset { get; init; }
    [JsonPropertyName("region")]
    public string? TimeZoneRegion { get; init; }
    [JsonPropertyName("type")]
    public string? TypeName { get; init; }
  }

  public class TapoErrorResponseException : TapoProtocolException {
    public TapoErrorResponseException(Uri requestEndPoint, string requestMethod, int rawErrorCode) {}

    public int RawErrorCode { get; }
    public string RequestMethod { get; }
  }

  public static class TapoHttpClientFactoryServiceCollectionExtensions {
    public static IServiceCollection AddTapoHttpClient(this IServiceCollection services, Action<HttpClient>? configureClient = null) {}
  }

  public class TapoPlugMonitoringData {
    public TapoPlugMonitoringData() {}

    [JsonConverter(typeof(TapoElectricEnergyInWattHourJsonConverter))]
    [JsonPropertyName("month_energy")]
    public decimal? CumulativeEnergyUsageThisMonth { get; init; }
    [JsonConverter(typeof(TapoElectricEnergyInWattHourJsonConverter))]
    [JsonPropertyName("today_energy")]
    public decimal? CumulativeEnergyUsageToday { get; init; }
    [JsonConverter(typeof(TapoElectricPowerInMilliWattJsonConverter))]
    [JsonPropertyName("current_power")]
    public decimal? CurrentPowerConsumption { get; init; }
    [JsonConverter(typeof(TapoLocalDateAndTimeJsonConverter))]
    [JsonPropertyName("local_time")]
    public DateTime? TimeStamp { get; init; }
    [JsonConverter(typeof(TimeSpanInMinutesJsonConverter))]
    [JsonPropertyName("month_runtime")]
    public TimeSpan? TotalOperatingTimeThisMonth { get; init; }
    [JsonConverter(typeof(TimeSpanInMinutesJsonConverter))]
    [JsonPropertyName("today_runtime")]
    public TimeSpan? TotalOperatingTimeToday { get; init; }
  }

  public class TapoProtocolException : InvalidOperationException {
    internal protected TapoProtocolException(string message, Uri endPoint, Exception? innerException) {}

    public Uri EndPoint { get; }
  }

  public static class TapoSessionProtocolSelectorServiceCollectionExtensions {
    public static IServiceCollection AddTapoProtocolSelector(this IServiceCollection services, Func<TapoDevice, TapoSessionProtocol?> selectProtocol) {}
    public static IServiceCollection AddTapoProtocolSelector(this IServiceCollection services, TapoSessionProtocol protocol) {}
    public static IServiceCollection AddTapoProtocolSelector(this IServiceCollection services, TapoSessionProtocolSelector selector) {}
  }

  public readonly struct TapoDeviceEnergyUsage {
    [JsonConverter(typeof(TapoElectricEnergyInWattHourJsonConverter))]
    [JsonPropertyName("past30")]
    public decimal? Past30Days { get; init; }
    [JsonConverter(typeof(TapoElectricEnergyInWattHourJsonConverter))]
    [JsonPropertyName("past7")]
    public decimal? Past7Days { get; init; }
    [JsonConverter(typeof(TapoElectricEnergyInWattHourJsonConverter))]
    [JsonPropertyName("today")]
    public decimal? Today { get; init; }
  }

  public readonly struct TapoDeviceExceptionHandling {
    public static readonly TapoDeviceExceptionHandling InvalidateEndPointAndRetry; // = "{ShouldRetry=True, RetryAfter=00:00:00, ShouldReestablishSession=False, ShouldWrapIntoTapoProtocolException=False, ShouldInvalidateEndPoint=True}"
    public static readonly TapoDeviceExceptionHandling InvalidateEndPointAndThrow; // = "{ShouldRetry=False, RetryAfter=00:00:00, ShouldReestablishSession=False, ShouldWrapIntoTapoProtocolException=False, ShouldInvalidateEndPoint=True}"
    public static readonly TapoDeviceExceptionHandling Retry; // = "{ShouldRetry=True, RetryAfter=00:00:00, ShouldReestablishSession=False, ShouldWrapIntoTapoProtocolException=False, ShouldInvalidateEndPoint=False}"
    public static readonly TapoDeviceExceptionHandling RetryAfterReestablishSession; // = "{ShouldRetry=True, RetryAfter=00:00:00, ShouldReestablishSession=True, ShouldWrapIntoTapoProtocolException=False, ShouldInvalidateEndPoint=False}"
    public static readonly TapoDeviceExceptionHandling Throw; // = "{ShouldRetry=False, RetryAfter=00:00:00, ShouldReestablishSession=False, ShouldWrapIntoTapoProtocolException=False, ShouldInvalidateEndPoint=False}"
    public static readonly TapoDeviceExceptionHandling ThrowAsTapoProtocolException; // = "{ShouldRetry=False, RetryAfter=00:00:00, ShouldReestablishSession=False, ShouldWrapIntoTapoProtocolException=True, ShouldInvalidateEndPoint=False}"

    public static TapoDeviceExceptionHandling CreateRetry(TimeSpan retryAfter, bool shouldReestablishSession = false) {}

    public TimeSpan RetryAfter { get; init; }
    public bool ShouldInvalidateEndPoint { get; init; }
    public bool ShouldReestablishSession { get; init; }
    public bool ShouldRetry { get; init; }
    public bool ShouldWrapIntoTapoProtocolException { get; init; }

    public override string ToString() {}
  }

  public readonly struct TapoDeviceOperatingTime {
    [JsonConverter(typeof(TimeSpanInMinutesJsonConverter))]
    [JsonPropertyName("past30")]
    public TimeSpan? Past30Days { get; init; }
    [JsonConverter(typeof(TimeSpanInMinutesJsonConverter))]
    [JsonPropertyName("past7")]
    public TimeSpan? Past7Days { get; init; }
    [JsonConverter(typeof(TimeSpanInMinutesJsonConverter))]
    [JsonPropertyName("today")]
    public TimeSpan? Today { get; init; }
  }
}

namespace Smdn.TPSmartHomeDevices.Tapo.Credentials {
  public interface ITapoCredential : IDisposable {
    void WritePasswordPropertyValue(Utf8JsonWriter writer);
    void WriteUsernamePropertyValue(Utf8JsonWriter writer);
  }

  public interface ITapoCredentialIdentity {
  }

  public interface ITapoCredentialProvider {
    ITapoCredential GetCredential(ITapoCredentialIdentity? identity);
    ITapoKlapCredential GetKlapCredential(ITapoCredentialIdentity? identity);
  }

  public interface ITapoKlapCredential : IDisposable {
    void WriteLocalAuthHash(Span<byte> destination);
  }

  public static class TapoCredentials {
    public const int HexSHA1HashSizeInBytes = 40;

    public static string ToBase64EncodedSHA1DigestString(ReadOnlySpan<char> str) {}
    public static string ToBase64EncodedString(ReadOnlySpan<char> str) {}
    public static bool TryComputeKlapLocalAuthHash(ReadOnlySpan<byte> username, ReadOnlySpan<byte> password, Span<byte> destination, out int bytesWritten) {}
    public static bool TryConvertToHexSHA1Hash(ReadOnlySpan<byte> input, Span<byte> destination, out int bytesWritten) {}
  }
}

namespace Smdn.TPSmartHomeDevices.Tapo.Json {
  public sealed class TapoBase64StringJsonConverter : JsonConverter<string> {
    public TapoBase64StringJsonConverter() {}

    public override string? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {}
    public override void Write(Utf8JsonWriter writer, string? @value, JsonSerializerOptions options) {}
  }

  public sealed class TapoElectricEnergyInWattHourJsonConverter : JsonConverter<decimal?> {
    public TapoElectricEnergyInWattHourJsonConverter() {}

    public override decimal? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {}
    public override void Write(Utf8JsonWriter writer, decimal? @value, JsonSerializerOptions options) {}
  }

  public sealed class TapoElectricPowerInMilliWattJsonConverter : TapoElectricPowerJsonConverter {
    public TapoElectricPowerInMilliWattJsonConverter() {}
  }

  public sealed class TapoElectricPowerInWattJsonConverter : TapoElectricPowerJsonConverter {
    public TapoElectricPowerInWattJsonConverter() {}
  }

  public abstract class TapoElectricPowerJsonConverter : JsonConverter<decimal?> {
    protected TapoElectricPowerJsonConverter() {}

    public override decimal? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {}
    public override void Write(Utf8JsonWriter writer, decimal? @value, JsonSerializerOptions options) {}
  }

  public sealed class TapoIPAddressJsonConverter : JsonConverter<IPAddress> {
    public TapoIPAddressJsonConverter() {}

    public override IPAddress? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {}
    public override void Write(Utf8JsonWriter writer, IPAddress @value, JsonSerializerOptions options) {}
  }

  public sealed class TapoLocalDateAndTimeJsonConverter : JsonConverter<DateTime?> {
    public TapoLocalDateAndTimeJsonConverter() {}

    public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {}
    public override void Write(Utf8JsonWriter writer, DateTime? @value, JsonSerializerOptions options) {}
  }
}

namespace Smdn.TPSmartHomeDevices.Tapo.Protocol {
  public interface ITapoPassThroughRequest : ITapoRequest {
  }

  public interface ITapoPassThroughResponse : ITapoResponse {
  }

  public interface ITapoRequest {
    string Method { get; }
  }

  public interface ITapoResponse {
    int ErrorCode { get; }
  }

  public enum TapoSessionProtocol : int {
    Klap = 1,
    SecurePassThrough = 0,
  }

  public static class HashAlgorithmExtensions {
    public static bool TryComputeHash(this HashAlgorithm algorithm, Span<byte> destination, ReadOnlySpan<byte> source0, ReadOnlySpan<byte> source1, ReadOnlySpan<byte> source2, ReadOnlySpan<byte> source3, out int bytesWritten) {}
    public static bool TryComputeHash(this HashAlgorithm algorithm, Span<byte> destination, ReadOnlySpan<byte> source0, ReadOnlySpan<byte> source1, ReadOnlySpan<byte> source2, out int bytesWritten) {}
  }

  public class KlapEncryptionAlgorithm {
    public KlapEncryptionAlgorithm(ReadOnlySpan<byte> localSeed, ReadOnlySpan<byte> remoteSeed, ReadOnlySpan<byte> userHash) {}

    public ReadOnlySpan<byte> IV { get; }
    public ReadOnlySpan<byte> Key { get; }
    public int SequenceNumber { get; }
    public ReadOnlySpan<byte> Signature { get; }

    public void Decrypt(ReadOnlySpan<byte> encryptedText, int sequenceNumber, IBufferWriter<byte> destination) {}
    public int Encrypt(ReadOnlySpan<byte> rawText, IBufferWriter<byte> destination) {}
    public void Encrypt(ReadOnlySpan<byte> rawText, int sequenceNumber, IBufferWriter<byte> destination) {}
  }

  public class SecurePassThroughInvalidPaddingException : SystemException {
    public SecurePassThroughInvalidPaddingException(string message, Exception? innerException) {}
  }

  public sealed class SecurePassThroughJsonConverterFactory :
    JsonConverterFactory,
    IDisposable
  {
    public SecurePassThroughJsonConverterFactory(ITapoCredentialIdentity? identity, ICryptoTransform? encryptorForPassThroughRequest, ICryptoTransform? decryptorForPassThroughResponse, JsonSerializerOptions? baseJsonSerializerOptionsForPassThroughMessage, ILogger? logger = null) {}

    public override bool CanConvert(Type typeToConvert) {}
    public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options) {}
    public void Dispose() {}
  }

  public sealed class TapoClient : IDisposable {
    public const int DefaultPort = 80;

    public static IHttpClientFactory DefaultHttpClientFactory { get; }

    public TapoClient(EndPoint endPoint, IHttpClientFactory? httpClientFactory = null, ILogger? logger = null) {}

    public Uri EndPointUri { get; }
    public TapoSession? Session { get; }
    public TimeSpan? Timeout { get; set; }

    public ValueTask AuthenticateAsync(ITapoCredentialIdentity? identity, ITapoCredentialProvider credential, CancellationToken cancellationToken = default) {}
    public ValueTask AuthenticateAsync(TapoSessionProtocol protocol, ITapoCredentialIdentity? identity, ITapoCredentialProvider credential, CancellationToken cancellationToken = default) {}
    public void Dispose() {}
    public ValueTask<TResponse> SendRequestAsync<TRequest, TResponse>(CancellationToken cancellationToken = default) where TRequest : ITapoPassThroughRequest, new() where TResponse : ITapoPassThroughResponse {}
    public ValueTask<TResponse> SendRequestAsync<TRequest, TResponse>(TRequest request, CancellationToken cancellationToken = default) where TRequest : notnull, ITapoPassThroughRequest where TResponse : ITapoPassThroughResponse {}
  }

  public abstract class TapoSession : IDisposable {
    public DateTime ExpiresOn { get; }
    public bool HasExpired { get; }
    public abstract TapoSessionProtocol Protocol { get; }
    public string? SessionId { get; }
    public abstract string? Token { get; }

    protected virtual void Dispose(bool disposing) {}
    public void Dispose() {}
  }

  public static class TapoSessionCookieUtils {
    public static bool TryGetCookie(HttpResponseMessage response, out string? sessionId, out int? sessionTimeout) {}
    public static bool TryGetCookie(IEnumerable<string>? cookieValues, out string? sessionId, out int? sessionTimeout) {}
    public static bool TryParseCookie(ReadOnlySpan<char> cookie, out string? id, out int? timeout) {}
  }

  public abstract class TapoSessionProtocolSelector {
    protected TapoSessionProtocolSelector() {}

    public abstract TapoSessionProtocol? SelectProtocol(TapoDevice device);
  }

  public readonly struct GetCurrentPowerRequest : ITapoPassThroughRequest {
    [JsonPropertyName("method")]
    [JsonPropertyOrder(0)]
    public string Method { get; }
    [JsonPropertyName("requestTimeMils")]
    public long RequestTimeMilliseconds { get; }
  }

  public readonly struct GetDeviceInfoRequest : ITapoPassThroughRequest {
    [JsonPropertyName("method")]
    [JsonPropertyOrder(0)]
    public string Method { get; }
    [JsonPropertyName("requestTimeMils")]
    public long RequestTimeMilliseconds { get; }
  }

  public readonly struct GetDeviceUsageRequest : ITapoPassThroughRequest {
    [JsonPropertyName("method")]
    [JsonPropertyOrder(0)]
    public string Method { get; }
    [JsonPropertyName("requestTimeMils")]
    public long RequestTimeMilliseconds { get; }
  }

  public readonly struct GetEnergyUsageRequest : ITapoPassThroughRequest {
    [JsonPropertyName("method")]
    [JsonPropertyOrder(0)]
    public string Method { get; }
    [JsonPropertyName("requestTimeMils")]
    public long RequestTimeMilliseconds { get; }
  }

  public readonly struct HandshakeRequest : ITapoRequest {
    public readonly struct RequestParameters {
      [JsonPropertyName("key")]
      public string Key { get; init; }
      [JsonPropertyName("requestTimeMils")]
      public long RequestTimeMilliseconds { get; }
    }

    public HandshakeRequest(string key) {}

    [JsonPropertyName("method")]
    [JsonPropertyOrder(0)]
    public string Method { get; }
    [JsonPropertyName("params")]
    public HandshakeRequest.RequestParameters Parameters { get; }
  }

  public readonly struct HandshakeResponse : ITapoResponse {
    public readonly struct ResponseResult {
      [JsonPropertyName("key")]
      public string? Key { get; init; }
    }

    [JsonPropertyName("error_code")]
    public int ErrorCode { get; init; }
    [JsonPropertyName("result")]
    public HandshakeResponse.ResponseResult Result { get; init; }
  }

  public readonly struct LoginDeviceRequest : ITapoPassThroughRequest {
    public LoginDeviceRequest(ITapoCredentialProvider credential) {}

    [JsonPropertyName("method")]
    [JsonPropertyOrder(0)]
    public string Method { get; }
    [JsonPropertyName("params")]
    public ITapoCredentialProvider Parameters { get; }
    [JsonPropertyName("requestTimeMils")]
    public long RequestTimeMilliseconds { get; }
  }

  public readonly struct LoginDeviceResponse : ITapoPassThroughResponse {
    public readonly struct ResponseResult {
      [JsonPropertyName("token")]
      public string Token { get; init; }
    }

    [JsonPropertyName("error_code")]
    public int ErrorCode { get; init; }
    [JsonPropertyName("result")]
    public LoginDeviceResponse.ResponseResult Result { get; init; }
  }

  public readonly struct PassThroughResponse<TResult> : ITapoPassThroughResponse {
    [JsonPropertyName("error_code")]
    public int ErrorCode { get; init; }
    [JsonPropertyName("result")]
    public TResult Result { get; init; }
  }

  public readonly struct SecurePassThroughRequest<TPassThroughRequest> : ITapoRequest where TPassThroughRequest : notnull, ITapoPassThroughRequest {
    public readonly struct RequestParams where TPassThroughRequest : notnull, ITapoPassThroughRequest {
      [JsonPropertyName("request")]
      public TPassThroughRequest PassThroughRequest { get; init; }
    }

    public SecurePassThroughRequest(TPassThroughRequest passThroughRequest) {}

    [JsonPropertyName("method")]
    [JsonPropertyOrder(0)]
    public string Method { get; }
    [JsonPropertyName("params")]
    public SecurePassThroughRequest<TPassThroughRequest>.RequestParams Params { get; }
  }

  public readonly struct SecurePassThroughResponse<TPassThroughResponse> : ITapoResponse where TPassThroughResponse : ITapoPassThroughResponse {
    public readonly struct ResponseResult where TPassThroughResponse : notnull, ITapoPassThroughResponse {
      [JsonPropertyName("response")]
      public TPassThroughResponse PassThroughResponse { get; init; }
    }

    public SecurePassThroughResponse(int errorCode, TPassThroughResponse passThroughResponse) {}

    [JsonPropertyName("error_code")]
    public int ErrorCode { get; init; }
    [JsonPropertyName("result")]
    public SecurePassThroughResponse<TPassThroughResponse>.ResponseResult Result { get; init; }
  }

  public readonly struct SetDeviceInfoRequest<TParameters> : ITapoPassThroughRequest {
    public SetDeviceInfoRequest(string terminalUuid, TParameters parameters) {}

    [JsonPropertyName("method")]
    [JsonPropertyOrder(0)]
    public string Method { get; }
    [JsonPropertyName("params")]
    public TParameters Parameters { get; }
    [JsonPropertyName("requestTimeMils")]
    public long RequestTimeMilliseconds { get; }
    [JsonPropertyName("terminalUUID")]
    public string TerminalUuid { get; }
  }
}
// API list generated by Smdn.Reflection.ReverseGenerating.ListApi.MSBuild.Tasks v1.3.2.0.
// Smdn.Reflection.ReverseGenerating.ListApi.Core v1.2.0.0 (https://github.com/smdn/Smdn.Reflection.ReverseGenerating)
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Smdn.TPSmartHomeDevices.Tapo:

Package Downloads
Smdn.TPSmartHomeDevices The ID prefix of this package has been reserved for one of the owners of this package by NuGet.org.

A meta package that addes the dependency of Smdn.TPSmartHomeDevices.Kasa, Smdn.TPSmartHomeDevices.Tapo and Smdn.TPSmartHomeDevices.MacAddressEndPoint.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
2.0.0 132 1/23/2024
2.0.0-preview5 68 1/18/2024
2.0.0-preview4 72 1/16/2024
2.0.0-preview3 89 1/8/2024
2.0.0-preview2 170 11/1/2023
2.0.0-preview1 83 10/31/2023
1.0.1 188 5/14/2023
1.0.0 361 5/2/2023
1.0.0-rc1 220 4/27/2023