Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ The following devices have been tested and confirmed as working. If your device
- **Wall Switches**: S210, S220, S500, S500D, S505, S505D
- **Bulbs**: L430P, L510B, L510E, L530B, L530E, L535E, L630
- **Light Strips**: L900-10, L900-5, L920-5, L930-5
- **Cameras**: C100, C110, C210, C220, C225, C325WB, C520WS, C720, TC65, TC70
- **Cameras**: C100, C110, C210, C220, C225, C325WB, C460, C520WS, C720, TC65, TC70
- **Doorbells and chimes**: D100C, D130, D230
- **Vacuums**: RV20 Max Plus, RV30 Max
- **Hubs**: H100, H200
Expand Down
2 changes: 2 additions & 0 deletions SUPPORTED.md
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,8 @@ All Tapo devices require authentication.<br>Hub-Connected Devices may work acros
- Hardware: 2.0 (US) / Firmware: 1.0.11
- **C325WB**
- Hardware: 1.0 (EU) / Firmware: 1.1.17
- **C460**
- Hardware: 1.0 (CA) / Firmware: 1.2.0
- **C520WS**
- Hardware: 1.0 (US) / Firmware: 1.2.8
- **C720**
Expand Down
88 changes: 56 additions & 32 deletions kasa/smartcam/modules/battery.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
"""Implementation of baby cry detection module."""
"""Implementation of smartcam battery module."""

from __future__ import annotations

import logging
from typing import Any

from ...feature import Feature
from ..smartcammodule import SmartCamModule
Expand Down Expand Up @@ -44,32 +45,37 @@ def _initialize_features(self) -> None:
)
)

self._add_feature(
Feature(
self._device,
"battery_temperature",
"Battery temperature",
container=self,
attribute_getter="battery_temperature",
icon="mdi:battery",
unit_getter=lambda: "celsius",
category=Feature.Category.Debug,
type=Feature.Type.Sensor,
# Optional on some battery cameras (e.g., C460).
if self._optional_float_sysinfo("battery_temperature") is not None:
self._add_feature(
Feature(
self._device,
"battery_temperature",
"Battery temperature",
container=self,
attribute_getter="battery_temperature",
icon="mdi:battery",
unit_getter=lambda: "celsius",
category=Feature.Category.Debug,
type=Feature.Type.Sensor,
)
)
)
self._add_feature(
Feature(
self._device,
"battery_voltage",
"Battery voltage",
container=self,
attribute_getter="battery_voltage",
icon="mdi:battery",
unit_getter=lambda: "V",
category=Feature.Category.Debug,
type=Feature.Type.Sensor,

if self._optional_float_sysinfo("battery_voltage") is not None:
self._add_feature(
Feature(
self._device,
"battery_voltage",
"Battery voltage",
container=self,
attribute_getter="battery_voltage",
icon="mdi:battery",
unit_getter=lambda: "V",
category=Feature.Category.Debug,
type=Feature.Type.Sensor,
)
)
)

self._add_feature(
Feature(
self._device,
Expand All @@ -83,6 +89,18 @@ def _initialize_features(self) -> None:
)
)

def _optional_float_sysinfo(self, key: str) -> float | None:
"""Return sys_info[key] as float, or None if not available or invalid."""
v_any: Any = self._device.sys_info.get(key)
if v_any in (None, "NO"):
return None

try:
# Accept ints/floats and numeric strings.
return float(v_any)
except (TypeError, ValueError):
return None

def query(self) -> dict:
"""Query to execute during the update cycle."""
return {}
Expand All @@ -98,16 +116,22 @@ def battery_low(self) -> bool:
return self._device.sys_info["low_battery"]

@property
def battery_temperature(self) -> bool:
"""Return battery voltage in C."""
return self._device.sys_info["battery_temperature"]
def battery_temperature(self) -> float | None:
"""Return battery temperature in °C (if available)."""
return self._optional_float_sysinfo("battery_temperature")

@property
def battery_voltage(self) -> bool:
"""Return battery voltage in V."""
return self._device.sys_info["battery_voltage"] / 1_000
def battery_voltage(self) -> float | None:
"""Return battery voltage in V (if available)."""
v = self._optional_float_sysinfo("battery_voltage")
return None if v is None else v / 1_000

@property
def battery_charging(self) -> bool:
"""Return True if battery is charging."""
return self._device.sys_info["battery_voltage"] != "NO"
v = self._device.sys_info.get("battery_charging")
if isinstance(v, bool):
return v
if v is None:
return False
return str(v).strip().lower() in ("yes", "true", "1", "charging", "on")
Loading
Loading