# Change Log

All notable changes to this project will be documented in this
file. This change log follows the conventions of
[keepachangelog.com][keepachangelog].

## [Rust Unreleased][Unreleased]

## [Python Unreleased][Unreleased]

## [Rust v0.8.10][v0.8.10] - 2026-02-22

### Fixed

- `HubHandler::s200d`: fixed an issue where the method was incorrectly filtering for `S200B` devices instead of `S200D` devices.

## [Python v0.8.10][v0.8.10] - 2026-02-22

### Fixed

- `HubHandler.s200d`: fixed an issue where the method was incorrectly filtering for `S200B` devices instead of `S200D` devices.

## [Rust v0.8.9][v0.8.9] - 2026-02-21

### Added

- `RgbicLightStripHandler`: added `set_segment_effect` method to apply lighting effects to individual segments of RGBIC light strips, enabling the newer effects available in the Tapo app that cannot be achieved through the `set_lighting_effect` method. (thanks to @Oliyy)
- `HubHandler`: added `s200d` method to create handlers for the S200D smart dimmer devices. (thanks to @mibofra)
- `EnergyUsageResult`: re-added the `current_power` property. It was removed in v0.8.6 because some energy-monitoring plugs omit it, but it is back as optional since it provides higher precision than `get_current_power`. (thanks to @nazamhussain)
- `EnergyUsageResult`: added the `electricity_charge` property to represent electricity charge/cost data reported by the device using the tariff configured in the Tapo app. (thanks to @nazamhussain)

### Changed

- `S200BHandler`: has been renamed to `S200Handler` to better reflect its purpose when used for both S200B and S200D devices.
- `S200BResult`: has been renamed to `S200Result` to better reflect its purpose when used for both S200B and S200D devices.
- `S200BRotationParams`: has been renamed to `S200RotationParams` to better reflect its purpose when used for both S200B and S200D devices.
- `S200BLog`: has been renamed to `S200Log` to better reflect its purpose when used for both S200B and S200D devices.

## [Python v0.8.9][v0.8.9] - 2026-02-21

### Added

- `RgbicLightStripHandler`: added `set_segment_effect` method to apply lighting effects to individual segments of RGBIC light strips, enabling the newer effects available in the Tapo app that cannot be achieved through the `set_lighting_effect` method. (thanks to @Oliyy)
- `HubHandler`: added `s200d` method to create handlers for the S200D smart dimmer devices. (thanks to @mibofra)
- `EnergyUsageResult`: re-added the `current_power` property. It was removed in v0.8.6 because some energy-monitoring plugs omit it, but it is back as optional since it provides higher precision than `get_current_power`. (thanks to @nazamhussain)
- `EnergyUsageResult`: added the `electricity_charge` property to represent electricity charge/cost data reported by the device using the tariff configured in the Tapo app. (thanks to @nazamhussain)

### Changed

- `S200BHandler`: has been renamed to `S200Handler` to better reflect its purpose when used for both S200B and S200D devices.
- `S200BResult`: has been renamed to `S200Result` to better reflect its purpose when used for both S200B and S200D devices.
- `S200BRotationParams`: has been renamed to `S200RotationParams` to better reflect its purpose when used for both S200B and S200D devices.
- `S200BLog`: has been renamed to `S200Log` to better reflect its purpose when used for both S200B and S200D devices.

## [Rust v0.8.8][v0.8.8] - 2025-11-23

### Added

- `TapoResponseError`: added `Forbidden` variant to represent authentication failures when Third-Party Compatibility is disabled in the Tapo app.

### Changed

- `TapoResponseError`: renamed variant `InvalidCredentials` to `Unauthorized` and updated the variant to include `code` and `description` for improved error context.

## [Python v0.8.8][v0.8.8] - 2025-11-23

### Added

- `Tapo` Exception: added `Forbidden` variant to represent authentication failures when Third-Party Compatibility is disabled in the Tapo app.

### Changed

- `Tapo` Exception: renamed variant `InvalidCredentials` to `Unauthorized` and updated the variant to include `code` and `description` for improved error context.

### Removed

- Dropped support for Python 3.9 and 3.10 (both no longer supported upstream). The minimum required version is now Python 3.11.

## [Rust v0.8.7][v0.8.7] - 2025-11-01

### Added
- `HubHandler`: added the `device_reboot` and `device_reset` methods.
- `PowerStripEnergyMonitoringHandler`: added the `device_reboot` and `device_reset` methods.
- `PowerStripHandler`: added the `device_reboot` and `device_reset` methods.
- `ColorLightHandler`: added the `device_reboot` method.
- `LightHandler`: added the `device_reboot` method.
- `PlugEnergyMonitoringHandler`: added the `device_reboot` method.
- `PlugHandler`: added the `device_reboot` method.
- `RgbicLightStripHandler`: added the `device_reboot` method.
- `RgbLightStripHandler`: added the `device_reboot` method.

### Changed

- `device_reset`: now requires the `DeviceManagementExt` trait to be in scope. The newly added `device_reboot` method also requires this trait.

## [Python v0.8.7][v0.8.7] - 2025-11-01

### Added

- `tapo`: added support for Python 3.14.
- `HubHandler`: added the `device_reboot` and `device_reset` methods.
- `PowerStripEnergyMonitoringHandler`: added the `device_reboot` and `device_reset` methods.
- `PowerStripHandler`: added the `device_reboot` and `device_reset` methods.
- `ColorLightHandler`: added the `device_reboot` method.
- `LightHandler`: added the `device_reboot` method.
- `PlugEnergyMonitoringHandler`: added the `device_reboot` method.
- `PlugHandler`: added the `device_reboot` method.
- `RgbicLightStripHandler`: added the `device_reboot` method.
- `RgbLightStripHandler`: added the `device_reboot` method.

## [Rust v0.8.6][v0.8.6] - 2025-09-25

### Added

- `PlugEnergyMonitoringHandler`: added `get_power_data` method to retrieve historical power data (every 5 minutes & hourly) for energy-monitoring plugs (P110, P110M, P115). The `PowerDataInterval` enum allows specifying the desired interval.
- `PowerStripPlugEnergyMonitoringHandler`: added the following energy monitoring methods: `get_current_power`, `get_device_usage`, `get_energy_usage`, `get_energy_data`, `get_power_data`.

### Changed

- `PlugEnergyMonitoringHandler`: `EnergyDataResult` has been redesigned to provide better ergonomics by attaching a start date time to each interval entry.

### Removed

- `EnergyUsageResult`: the `current_power` field has been removed from the struct because not all energy-monitoring plugs provide this data. Instead, use the `get_current_power` method to retrieve the current power.

## [Python v0.8.6][v0.8.6] - 2025-09-25

### Added

- `PlugEnergyMonitoringHandler`: added `get_power_data` method to retrieve historical power data (every 5 minutes & hourly) for energy-monitoring plugs (P110, P110M, P115). The `PowerDataInterval` enum allows specifying the desired interval.
- `PowerStripPlugEnergyMonitoringHandler`: added the following energy monitoring methods: `get_current_power`, `get_device_usage`, `get_energy_usage`, `get_energy_data`, `get_power_data`.

### Changed

- `PlugEnergyMonitoringHandler`: `EnergyDataResult` has been redesigned to provide better ergonomics by attaching a start date time to each interval entry.

### Removed

- `EnergyUsageResult`: the `current_power` field has been removed from the class because not all energy-monitoring plugs provide this data. Instead, use the `get_current_power` method to retrieve the current power.

## [Rust v0.8.5][v0.8.5] - 2025-09-18

### Added

- `ApiClient`: added `discover_devices` method to discover all Tapo devices on the local network. This works even with dynamic or unknown IPs, but is slower since it scans the entire network and waits for device responses.
- `PowerStripPlugHandler`: added support for P306 power strips.
- Added `PowerStripEnergyMonitoringHandler`, `PowerStripPlugEnergyMonitoringHandler`, and `PowerStripPlugEnergyMonitoringResult` to support energy-monitoring power strips (P304M, P316M). Non-monitoring models (P300, P306) will continue using the pre-existing `PowerStripPlugHandler`.
- `PowerStripPlugResult`: added `default_states` field.

### Changed

- `DeviceInfoPowerStripResult`: changed `time_diff` from `Option<i64>` to `i64`.

### Fixed

- `PowerStripPlugResult`: removed `charging_status`, `overcurrent_status`, and `power_protection_status` (not returned by P300/P306).

## [Python v0.8.5][v0.8.5] - 2025-09-18

### Added

- `ApiClient`: added `discover_devices` method to discover all Tapo devices on the local network. This works even with dynamic or unknown IPs, but is slower since it scans the entire network and waits for device responses.
- `PowerStripPlugHandler`: added support for P306 power strips.
- Added `PowerStripEnergyMonitoringHandler`, `PowerStripPlugEnergyMonitoringHandler`, and `PowerStripPlugEnergyMonitoringResult` to support energy-monitoring power strips (P304M, P316M). Non-monitoring models (P300, P306) will continue using the pre-existing `PowerStripPlugHandler`.
- `PowerStripPlugResult`: added `default_states` field.

### Changed

- `DeviceInfoPowerStripResult`: changed `time_diff` from `Optional[int]` to `int`.

### Fixed

- `PowerStripPlugResult`: removed `charging_status`, `overcurrent_status`, and `power_protection_status` (not returned by P300/P306).

## [Rust v0.8.4][v0.8.4] - 2025-08-11

### Added

- The `default_states` property has been added to the `DeviceInfoPlugResult` struct to provide a more comprehensive overview of the plug's state.

### Fixed

- The `default_states` property value of the `DeviceInfoPlugEnergyMonitoringResult` struct has been changed from a struct to an enum to better reflect the actual response from the device.

## [Python v0.8.4][v0.8.4] - 2025-08-11

### Added

- The `default_states` property has been added to the `DeviceInfoPlugResult` class to provide a more comprehensive overview of the plug's state.

### Fixed

- The `default_states` property value of the `DeviceInfoPlugEnergyMonitoringResult` class has been changed from a class to an enum to better reflect the actual response from the device.

## [Rust v0.8.3][v0.8.3] - 2025-07-25

### Added

- Added support for the P316M power strips.
- The `charging_status`, `overcurrent_status`, and `power_protection_status` fields have been added to `PowerStripPlugResult`.

### Changed

- Enhanced the `InvalidCredentials` error with clearer guidance on common causes and how to address them.
- The `overheat_status` field in `PowerStripPlugResult` is now optional to support devices that omit this field.

### Removed

- Removed `nickname` from `DeviceInfoPowerStripResult` because it is not present in the response.

## [Python v0.8.3][v0.8.3] - 2025-07-25

### Added

- Added support for the P316M power strips.
- The `charging_status`, `overcurrent_status`, and `power_protection_status` fields have been added to `PowerStripPlugResult`.

### Changed

- Enhanced the `InvalidCredentials` error with clearer guidance on common causes and how to address them.
- The `overheat_status` field in `PowerStripPlugResult` is now optional to support devices that omit this field.

### Removed

- Removed `nickname` from `DeviceInfoPowerStripResult` because it is not present in the response.

## [Rust v0.8.2][v0.8.2] - 2025-05-19

### Added

- The `charging_status` field has been added to `DeviceInfoPlugEnergyMonitoringResult`.

### Changed

- The `overheat_status` field in `DeviceInfoPlugEnergyMonitoringResult` is now optional to support devices that omit this field after the latest firmware update (1.3.4 Build 250403 Rel.150504).

## [Python v0.8.2][v0.8.2] - 2025-05-19

### Added

- The `charging_status` field has been added to `DeviceInfoPlugEnergyMonitoringResult`.

### Changed

- The `overheat_status` field in `DeviceInfoPlugEnergyMonitoringResult` is now optional to support devices that omit this field after the latest firmware update (1.3.4 Build 250403 Rel.150504).

## [Rust v0.8.1][v0.8.1] - 2025-02-10

### Added

- Added functionality for controlling the alarm on the H100 hub via the `play_alarm` and `stop_alarm` methods in the `H100Handler`. Additionally, `get_supported_ringtone_list` is available to retrieve the list of supported ringtones for debugging purposes. (thanks to @kay)
- Added the ability to retrieve the color configuration (`hue`, `saturation`, `color_temperature`) for the `Color` enum values through the `get_color_config` method. (thanks to @WhySoBad)

### Changed

- The internal implementation of `H100Handler`'s `get_child_device_list` has been updated to fetch all pages, not just the first one.
- `H100Handler`'s `get_child_device_list_json` now includes a `start_index` parameter to fetch child devices starting from a specific index.

### Fixed

- Resolved an issue that caused the passthrough protocol test to incorrectly indicate support when it was not actually supported. (thanks to @WhySoBad)

## [Python v0.8.1][v0.8.1] - 2025-02-10

### Added

- Added functionality for controlling the alarm on the H100 hub via the `play_alarm` and `stop_alarm` methods in the `H100Handler`. Additionally, `get_supported_ringtone_list` is available to retrieve the list of supported ringtones for debugging purposes.
- Added the ability to retrieve the color configuration (`hue`, `saturation`, `color_temperature`) for the `Color` enum values through the `get_color_config` method. (thanks to @WhySoBad)

### Changed

- The internal implementation of `H100Handler`'s `get_child_device_list` has been updated to fetch all pages, not just the first one.
- `H100Handler`'s `get_child_device_list_json` now includes a `start_index` parameter to fetch child devices starting from a specific index.

### Fixed

- Resolved an issue that caused the passthrough protocol test to incorrectly indicate support when it was not actually supported. (thanks to @WhySoBad)

## [Rust v0.8.0][v0.8.0] - 2024-12-07

This marks the first unified release of the Rust and Python libraries. Moving forward, both libraries will be released simultaneously and will share the same version number.

### Added

- Added an example for the L900 light strips.

### Changed

- `LightingEffect`'s `fadeoff` field has been renamed to `fade_off`, and its `with_fadeoff` method has been renamed to `with_fade_off`.
- `LightingEffect`'s `new_with_random_id` function has been removed. The `new` function now creates a `LightingEffect` instance with a random ID by default.

## [Python v0.8.0][v0.8.0] - 2024-12-07

### Added

- Added support for the L900 light strips.
- Added support for the L920 and L930 light strips.
- Added support for Python 3.13.

## [Python v0.7.0][py-v0.7.0] - 2024-11-07

### Added

- Added support for the KE100 thermostatic radiator valve (TRV).

## [Rust v0.7.17][v0.7.17] - 2024-10-23

### Added

- Added support for the P304 power strip.

### Changed

- The `openssl` dependency has been replaced with native Rust alternatives to expand cross-compilation options, such as for Android, and to decrease build times (thanks to @rbock44).
- `PlugPowerStripHandler` has been renamed to `PowerStripPlugHandler` to be consistent with the rest of the library.
- `PlugPowerStripResult` has been renamed to `PowerStripPlugResult` to be consistent with the rest of the library.
- The `UsageByPeriodResult` fields `today`, `past7`, and `past30` have been updated to `Option<u64>` to handle cases where the API returns negative values, which will be represented as `None`.

### Fixed

- Updated all comments referencing Watts to confirm the correct units are specified.

## [Python v0.6.0][py-v0.6.0] - 2024-10-23

### Added

- Added support for the P300 and P304 power strips.
- Python logs can now capture entries from the underlying Rust library.

### Changed

- The `openssl` dependency has been replaced with native Rust alternatives to expand cross-compilation options, such as for Android, and to decrease build times (thanks to @rbock44).
- The `UsageByPeriodResult` fields `today`, `past7`, and `past30` have been updated to `Optional[int]` to handle cases where the API returns negative values, which will be represented as `null`.

### Fixed

- Updated all comments referencing Watts to confirm the correct units are specified.

## [Rust v0.7.16][v0.7.16] - 2024-09-27

### Added

- Added support for the L535 light bulbs.

### Fixed

- Fixed an issue that prevented the color from being set properly for the L535 light bulbs.

## [Python v0.5.1][py-v0.5.1] - 2024-09-27

### Added

- Added support for the L535 light bulbs.

### Fixed

- Fixed an issue that prevented the color from being set properly for the L535 light bulbs.

## [Rust v0.7.15][v0.7.15] - 2024-09-18

### Added

- The `LowBattery` variant has been added to the `S200BLog` enum.

### Changed

- The `t310` and `t315` methods of `HubHandler` can now create `T31XHandler` handlers for either of the two device types.
- The child device handlers for the H100 hub and the P300 power strip have been redesigned to eliminate the use of lifetimes, to facilitate FFI integrations.
- The comments of `start_timestamp` and `end_timestamp` fields in `EnergyDataResult` have been updated to better describe their purpose.
- `S200BRotationParams`'s field `degrees` has been renamed to `rotation_degrees`.

### Fixed

- Fixed an issue with the `Color` presets that triggered a validation error when attempting to set the `color` to `DarkRed`.

### Removed

- The deprecated `past24h`, `past7d`, `past30d` and `past1y` fields have been removed from `EnergyUsageResult`. This data is now available exclusively through `get_energy_data`'s `EnergyDataResult` response.

## [Python v0.5.0][py-v0.5.0] - 2024-09-18

### Added

- Added full support for the S200B switches through the `S200BHandler` handler.
- Added full support for the T100 sensors through the `T100Handler` handler.
- Added full support for the T110 sensors through the `T110Handler` handler.
- Added full support for the T300 sensors through the `T300Handler` handler.
- Added full support for the T310 and T315 sensors through the `T31XHandler` handler.

### Changed

- The comments of `start_timestamp` and `end_timestamp` fields in `EnergyDataResult` have been updated to better describe their purpose.

### Fixed

- Fixed an issue with the `Color` presets that triggered a validation error when attempting to set the `color` to `DarkRed`.

## [Rust v0.7.14][v0.7.14] - 2024-08-31

### Changed

- `DeviceInfoPlugEnergyMonitoringResult` has been added to support the P110 and P115 devices, which have different responses compared to the P100 and P105 devices.

### Fixed

- `DeviceInfoPlugResult` has been updated to correctly support the P100 and P105 devices.

## [Python v0.4.0][py-v0.4.0] - 2024-08-31

### Changed

- `DeviceInfoPlugEnergyMonitoringResult` has been added to support the P110 and P115 devices, which have different responses compared to the P100 and P105 devices.

### Fixed

- Resolved an issue that led to unrecoverable process hangs when a device request timed out.
- The concurrency of device handlers has been significantly enhanced by replacing all `Mutex` instances with `RwLock`.
- `DeviceInfoPlugResult` has been updated to correctly support the P100 and P105 devices.

## [Rust v0.7.13][v0.7.13] - 2024-08-26

### Changed

- To align with the latest API updates, the `overheated` field for plugs has been replaced by three enums: `overcurrent_status`, `overheat_status`, and `power_protection_status` (thanks to @padenot).

## [Python v0.3.2][py-v0.3.2] - 2024-08-26

### Changed

- To align with the latest API updates, the `overheated` field for plugs has been replaced by three enums: `overcurrent_status`, `overheat_status`, and `power_protection_status`.

## [Rust v0.7.12][v0.7.12] - 2024-06-27

### Changed

- H100's create child device handler methods now take a `HubDevice` `enum` instead of a `String` and are now `async` to allow for more flexibility. This enables the caller to find child devices by either device ID or nickname.
- `PlugIdentifier` has been renamed to `Plug`.
- `Plug::ByDeviceId` now verifies that the provided device ID is found and returns an `Error::DeviceNotFound` error when it's not.
- `HubDevice` variants now take a `String` instead of a `&str` to allow for more flexibility.
- `Plug` variants now take a `String` instead of a `&str` to allow for more flexibility.

### Fixed

- `ColorLightSetDeviceInfoParams` `hue` field validation has been changed from `between 1 and 360` to `between 0 and 360` to match the device's expected range.
- Fixed an issue where the `EnergyDataResult`'s `start_timestamp` and `end_timestamp` did not correctly adjust for timezone offsets.
- The `chrono` dependency has been updated to `0.4.34` to fix the minimum version requirement.

### Removed

- The `overheated` property has been removed from `DeviceInfoGenericResult` because it's not present in the response of all devices.

## [Python v0.3.1][py-v0.3.1] - 2024-06-27

### Fixed

- `ColorLightSetDeviceInfoParams` `hue` field validation has been changed from `between 1 and 360` to `between 0 and 360` to match the device's expected range.
- Fixed an issue where the `EnergyDataResult`'s `start_timestamp` and `end_timestamp` did not correctly adjust for timezone offsets.
- All handlers are now correctly exported and can be imported from the `tapo` module.

### Removed

- The `overheated` property has been removed from `DeviceInfoGenericResult` because it's not present in the response of all devices.

## [Rust v0.7.11][v0.7.11] - 2024-05-04

### Added

- Added support for the P300 power strip (thanks to @Michal-Szczepaniak).
- `RgbLightStripHandler` and `DeviceInfoRgbLightStripResult` have been added to support the L900 devices separately from the L530 and L630 devices.

### Changed

- `ChildDeviceResult` has been renamed to `ChildDeviceHubResult` to facilitate adding support for other devices with children.
- `ColorLightStripHandler` has been renamed to `RgbicLightStripHandler` to better reflect its purpose.
- `DeviceInfoColorLightStripResult` has been renamed to `DeviceInfoRgbicLightStripResult` to better reflect its purpose.

## [Python v0.3.0][py-v0.3.0] - 2024-05-04

### Added

- Added partial support for the H100 hub and its child devices. Currently, only the `get_device_info` function is supported for the child devices through the hub's `get_child_device_list` method.

### Changed

- A large number of types have been reorganized to me more in line with the Rust library. This includes moving many of them under the `requests` and `responses` sub modules.

### Removed

- `l900` has been removed from the `ApiClient` until proper support is added.

## [Rust v0.7.10][v0.7.10] - 2024-04-05

### Changed

- The implementation of `ApiClient::new` has been improved to allow for the return of `ApiClient` instead of `Result<ApiClient, Error>`.
- The default timeout for all requests has been reduced to 30 seconds from 300 seconds.
- `ApiClient::with_timeout` has been added to allow for the setting of a custom timeout for all requests (thanks to @skoky).

## [Python v0.2.1][py-v0.2.1] - 2024-04-05

### Changed

- The default timeout for all requests has been reduced to 30 seconds from 300 seconds.
- The `timeout_s` optional parameter has been added to the `ApiClient` constructor to allow for the setting of a custom timeout for all requests (thanks to @skoky).

## [Rust v0.7.9][v0.7.9] - 2024-01-27

### Changed

- The `send()` method of the `.set()` API now takes a reference to the device handler in order to allow for better ergonomics.

### Fixed

- The device info response for the L510, L520, and L610 devices has been fixed.

## [Python v0.2.0][py-v0.2.0] - 2024-01-27

### Added

- Added support for the L530, L630, and L900 color light bulbs.

### Fixed

- Fixed a misconfiguration that was preventing the sdist package from working properly.
- The device info response for the L510, L520, and L610 devices has been fixed.

## [Rust v0.7.8][v0.7.8] - 2024-01-22

### Added

- Added the `device_reset` method to all plugs and lights.

### Fixed

- The device info response for the L510, L520, and L610 devices has been fixed to have the `re_power_type` field as optional.

## [Python v0.1.5][py-v0.1.5] - 2024-01-22

### Added

- Added the `device_reset` method to all plugs and lights.

### Fixed

- The device info response for the L510, L520, and L610 devices has been fixed to have the `re_power_type` field as optional.

## [Rust v0.7.7][v0.7.7] - 2024-01-13

### Changed

- The `anyhow::anyhow!("Local hash does not match server hash")` error has been replaced with the more specific `tapo::TapoResponseError::InvalidCredentials` error.

### Fixed

- The `default_states` field that's part of the device info response has been changed for the L510, L520, and L610 devices to match the actual response from the device.
- A handful of edge cases around the Klap Protocol that were causing panics have been fixed to return `tapo::TapoResponseError::SessionTimeout` or `tapo::TapoResponseError::InvalidResponse` errors instead.

## [Python v0.1.4][py-v0.1.4] - 2024-01-13

### Changed

- The "Local hash does not match server hash" error has been replaced with the more specific `tapo::TapoResponseError::InvalidCredentials` error.

### Fixed

- The `default_states` field that's part of the device info response has been changed for the L510, L520, and L610 devices to match the actual response from the device.
- A handful of edge cases around the Klap Protocol that were causing panics have been fixed to return `tapo::TapoResponseError::SessionTimeout` or `tapo::TapoResponseError::InvalidResponse` errors instead.

## [Rust v0.7.6][v0.7.6] - 2023-11-25

### Added

- Added support for the KE100 thermostatic radiator valve (TRV) devices (thanks to @pwoerndle).

### Fixed

- Fixed an issue that was preventing the `nickname` field from being decoded in the `get_device_info` results of child devices of the H100 hub.

## [Rust v0.7.5][v0.7.5] - 2023-11-05

### Added

- Added support for the T300 water sensor.
- Added a dedicated handler for the L520 devices.

## [Python v0.1.3][py-v0.1.3] - 2023-11-04

### Added

- Added support for the L510, L520 and L610 light bulbs.

### Changed

- The minimum required version of Python has been changed to 3.8, up from 3.7.

### Fixed

- Fixed an issue that was preventing `get_device_info_json` from working on the plug devices.

## [Python v0.1.2][py-v0.1.2] - 2023-10-19

### Added

- Added support for generic devices.
- Added `get_device_info_json` to all currently supported devices.

## [Python v0.1.1][py-v0.1.1] - 2023-10-01

This is the first version of the Python wrapper library.
It supports the plug devices P100, P105, P110 and P115.

## [v0.7.4] - 2023-09-15

### Fixed

- Fixed the minimum version of the chrono dependency by setting it to 0.4.25.

### Changes

- `DeviceUsageResult` has been split into `DeviceUsageResult` and `DeviceUsageEnergyMonitoringResult`. The former is now returned for the P100 and P105 devices while the latter is returned for all the other devices that support energy monitoring.
- `EnergyMonitoringPlugHandler` has been renamed to `PlugEnergyMonitoringHandler`.
- All `___DeviceInfoResult` structs have been renamed to `DeviceInfo___Result`.
- All `___DefaultState` structs have been renamed to `Default___State`.

### Removed

- `get_device_usage` has been removed from the `GenericDeviceHandler` because it is not supported by all devices.

## [v0.7.3] - 2023-09-14

### Added

- Added support for the newly introduced KLAP protocol, which is required to interact with the latest firmware version of multiple devices.

### Changed

- All uses of `time` have been replaced with `chrono`:
  - `EnergyDataInterval`'s `time::OffsetDateTime` and `time::Date` fields have been replaced with `chrono::NaiveDate`.
  - `EnergyUsageResult::local_time` field is now `chrono::NaiveDateTime` instead of `time::OffsetDateTime`.
  - `EnergyDataResult::local_time` field is now `chrono::NaiveDateTime` instead of `time::OffsetDateTime`.
  - `TemperatureHumidityRecords`'s and `TemperatureHumidityRecord` `datetime` fields are now `chrono::DateTime<chrono::Utc>` instead of `time::OffsetDateTime`.
- `EnergyDataInterval::Hourly::start_datetime` and `EnergyDataInterval::Hourly::end_datetime` have been renamed to `start_date` and `end_date` because the time component is not required.
- The `login` function on all handlers has been renamed to `refresh_session` to better reflect its purpose and it now takes and returns a `&mut self` instead of `self`.
- `L510DeviceInfoResult` has been renamed to `LightDeviceInfoResult` to better reflect its purpose when used for L510 and L610 devices.
- `L530DeviceInfoResult` has been renamed to `ColorLightDeviceInfoResult` to better reflect its purpose when used for L530, L630 and L900 devices.
- `L930DeviceInfoResult` has been renamed to `ColorLightStripDeviceInfoResult` to better reflect its purpose when used for L920 and L930 devices.
- The `default_states` field of `LightDeviceInfoResult`, `ColorLightDeviceInfoResult`, `ColorLightStripDeviceInfoResult` and `PlugDeviceInfoResult` is now a struct instead of an enum.

## [v0.7.2] - 2023-08-21

### Added

- Added `get_current_power` to the `P110` and `P115` plugs. (thanks to @Michal-Szczepaniak)

## [v0.7.1] - 2023-05-30

### Added

- Added `get_temperature_humidity_records` to the `T310` and `T315` sensors.

### Changed

- The creation of device handlers has been simplified.

```rust
// old
let device = ApiClient::new(ip_address, tapo_username, tapo_password)?
    .l530()
    .login()
    .await?;

// new
let device = ApiClient::new(tapo_username, tapo_password)?
    .l530(ip_address)
    .await?;
```

- The creation of child device handlers has been reworked so that they can be created without requiring a call to `get_child_device_list` when the child Device ID is known.
- `ApiClient` now implements `Clone` to allow for a cheaper duplication of the client.

### Removed

- The `L510` and `L610` devices no longer expose the `set()` API because changing multiple properties simultaneously does not make sense for these devices.

## [v0.7.0] - 2023-05-26

### Added

- Added initial support for the H100 device, the S200B switch and the T100, T110, T310, T315 sensors. The child devices currently support `get_device_info` and `get_trigger_logs`.
- All responses now derive `serde::Serialize` to allow for more straightforward consumer serialisation. (thanks to @ClementNerma)
- `ApiClient` has been marked as both `Send` and `Sync` to allow for sharing between threads. (thanks to @ClementNerma)

### Changed

- `GenericDeviceInfoResult`'s `device_on` property has been made optional to accommodate devices that do not provide this field.

## [v0.6.0] - 2023-05-08

### Added

- Added support for the L920 and L930 light strips. The highlight is the `tapo::ColorLightStripHandler::set_lighting_effect` function, which supports all the effects that the Tapo app contains alongside user-defined effects.
- Added support for the L900 light strips.
- Each supported device now has it's own handler creator.

### Changed

- `set_*` functions like `tapo::requests::ColorLightSetDeviceInfoParams::set_brightness` now return `Self` instead of `Result<Self, Error>` to allow for better ergonomics. The validations will now run when `tapo::requests::ColorLightSetDeviceInfoParams::send` is called.
- `tapo::requests::L510SetDeviceInfoParams` has been renamed to `tapo::requests::LightSetDeviceInfoParams` to better reflect its purpose when used for L510, L610, and L900 devices.
- `tapo::requests::L530SetDeviceInfoParams` has been renamed to `tapo::requests::ColorLightSetDeviceInfoParams` to better reflect its purpose when used for L530, L630, L920 and L930 devices.
- `tapo::P100Handler` has been renamed to `tapo::PlugHandler`.
- `tapo::P110Handler` has been renamed to `tapo::EnergyMonitoringPlugHandler`.
- `tapo::L510Handler` has been renamed to `tapo::LightHandler`.
- `tapo::L530Handler` has been renamed to `tapo::ColorLightHandler`.
- `tapo::L930Handler` has been renamed to `tapo::ColorLightStripHandler`.

## [v0.5.0] - 2023-04-16

### Changed

- The creation of an API Client for a specific device is now done through handler methods on the `ApiClient` struct. This allows for a more ergonomic API. (thanks to [Octocrab](https://github.com/XAMPPRocky/octocrab) for inspirations)

```rust
// old
let device = ApiClient::<L530>::new(ip_address, tapo_username, tapo_password, true).await?;

// new
let device = ApiClient::new(ip_address, tapo_username, tapo_password)?
    .l530()
    .login()
    .await?;
```

- `ApiClient::new` parameters are now `impl Into<String>` instead of `String` to allow for more flexibility.
- Error handling has been reworked. All functions that could error now return a `Result<..., tapo::Error>`.

## [v0.4.0] - 2023-02-25

### Added

- `get_energy_data` is now available for the *P110* devices. (thanks to @kuhschnappel)

### Changed

- `EnergyUsageResult`'s `past24h`, `past7d`, `past30d` and `past1y` fields are now deprecated. `get_energy_data` should be used instead. (thanks to @felixhauptmann)

## [v0.3.1] - 2023-02-19

### Added

- `examples/tapo_generic_device_toggle.rs` demonstrates how `device_info` can be used to assess the current status of a generic device and toggle it.

### Changed

- `on_time` is now optional for the `L510` and `L530` devices because the v2 hardware no longer returns it.

## [v0.3.0] - 2022-11-20

### Added

- The `set` API allows multiple properties to be set in a single request for the _L510_ and _L530_ devices.

### Changed

- `tapo::Color` has been moved to `tapo::requests::Color`.
- `GenericDeviceInfoResult::on_time` has been changed from `u64` to `Option<u64>` because some devices (like *L930*) do not provide this field.
- All response structs have been moved under `tapo::responses`.
- The docs have been improved.

## [v0.2.1] - 2022-08-07

### Changed

- `latitude` and `longitude` in `GenericDeviceInfoResult`, `L510DeviceInfoResult`, `L530DeviceInfoResult` and `PlugDeviceInfoResult` are now signed integers to accommodate for incoming responses with negative numbers. (thanks to @JPablomr)

## [v0.2.0] - 2022-06-13

### Added

- Generic Device example.

### Changed

- `get_device_usage` has been moved to the base implementation so that all devices have access to it.
- `Color` now implements `serde::Serialize` and `serde::Deserialize`.

### Removed

- `TapoDeviceExt` is no longer has `Default` and `serde::Serialize` as supersets.

## [v0.1.0] - 2022-06-07

### Initial Release of Tapo

[Unreleased]: https://github.com/mihai-dinculescu/tapo
[v0.8.10]: https://github.com/mihai-dinculescu/tapo/tree/v0.8.10
[v0.8.9]: https://github.com/mihai-dinculescu/tapo/tree/v0.8.9
[v0.8.8]: https://github.com/mihai-dinculescu/tapo/tree/v0.8.8
[v0.8.7]: https://github.com/mihai-dinculescu/tapo/tree/v0.8.7
[v0.8.6]: https://github.com/mihai-dinculescu/tapo/tree/v0.8.6
[v0.8.5]: https://github.com/mihai-dinculescu/tapo/tree/v0.8.5
[v0.8.4]: https://github.com/mihai-dinculescu/tapo/tree/v0.8.4
[v0.8.3]: https://github.com/mihai-dinculescu/tapo/tree/v0.8.3
[v0.8.2]: https://github.com/mihai-dinculescu/tapo/tree/v0.8.2
[v0.8.1]: https://github.com/mihai-dinculescu/tapo/tree/v0.8.1
[v0.8.0]: https://github.com/mihai-dinculescu/tapo/tree/v0.8.0
[py-v0.7.0]: https://github.com/mihai-dinculescu/tapo/tree/py-v0.7.0
[v0.7.17]: https://github.com/mihai-dinculescu/tapo/tree/v0.7.17
[py-v0.6.0]: https://github.com/mihai-dinculescu/tapo/tree/py-v0.6.0
[v0.7.16]: https://github.com/mihai-dinculescu/tapo/tree/v0.7.16
[py-v0.5.1]: https://github.com/mihai-dinculescu/tapo/tree/py-v0.5.1
[v0.7.15]: https://github.com/mihai-dinculescu/tapo/tree/v0.7.15
[py-v0.5.0]: https://github.com/mihai-dinculescu/tapo/tree/py-v0.5.0
[v0.7.14]: https://github.com/mihai-dinculescu/tapo/tree/v0.7.14
[py-v0.4.0]: https://github.com/mihai-dinculescu/tapo/tree/py-v0.4.0
[v0.7.13]: https://github.com/mihai-dinculescu/tapo/tree/v0.7.13
[py-v0.3.2]: https://github.com/mihai-dinculescu/tapo/tree/py-v0.3.2
[v0.7.12]: https://github.com/mihai-dinculescu/tapo/tree/v0.7.12
[py-v0.3.1]: https://github.com/mihai-dinculescu/tapo/tree/py-v0.3.1
[v0.7.11]: https://github.com/mihai-dinculescu/tapo/tree/v0.7.11
[py-v0.3.0]: https://github.com/mihai-dinculescu/tapo/tree/py-v0.3.0
[v0.7.10]: https://github.com/mihai-dinculescu/tapo/tree/v0.7.10
[py-v0.2.1]: https://github.com/mihai-dinculescu/tapo/tree/py-v0.2.1
[v0.7.9]: https://github.com/mihai-dinculescu/tapo/tree/v0.7.9
[py-v0.2.0]: https://github.com/mihai-dinculescu/tapo/tree/py-v0.2.0
[v0.7.8]: https://github.com/mihai-dinculescu/tapo/tree/v0.7.8
[py-v0.1.5]: https://github.com/mihai-dinculescu/tapo/tree/py-v0.1.5
[v0.7.7]: https://github.com/mihai-dinculescu/tapo/tree/v0.7.7
[py-v0.1.4]: https://github.com/mihai-dinculescu/tapo/tree/py-v0.1.4
[v0.7.6]: https://github.com/mihai-dinculescu/tapo/tree/v0.7.6
[v0.7.5]: https://github.com/mihai-dinculescu/tapo/tree/v0.7.5
[py-v0.1.3]: https://github.com/mihai-dinculescu/tapo/tree/py-v0.1.3
[py-v0.1.2]: https://github.com/mihai-dinculescu/tapo/tree/py-v0.1.2
[py-v0.1.1]: https://github.com/mihai-dinculescu/tapo/tree/py-v0.1.1
[v0.7.4]: https://github.com/mihai-dinculescu/tapo/tree/v0.7.4
[v0.7.3]: https://github.com/mihai-dinculescu/tapo/tree/v0.7.3
[v0.7.2]: https://github.com/mihai-dinculescu/tapo/tree/v0.7.2
[v0.7.1]: https://github.com/mihai-dinculescu/tapo/tree/v0.7.1
[v0.7.0]: https://github.com/mihai-dinculescu/tapo/tree/v0.7.0
[v0.6.0]: https://github.com/mihai-dinculescu/tapo/tree/v0.6.0
[v0.5.0]: https://github.com/mihai-dinculescu/tapo/tree/v0.5.0
[v0.4.0]: https://github.com/mihai-dinculescu/tapo/tree/v0.4.0
[v0.3.1]: https://github.com/mihai-dinculescu/tapo/tree/v0.3.1
[v0.3.0]: https://github.com/mihai-dinculescu/tapo/tree/v0.3.0
[v0.2.1]: https://github.com/mihai-dinculescu/tapo/tree/v0.2.1
[v0.2.0]: https://github.com/mihai-dinculescu/tapo/tree/v0.2.0
[v0.1.0]: https://github.com/mihai-dinculescu/tapo/tree/v0.1.0
[keepachangelog]: https://keepachangelog.com
