Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pull] master from xZetsubou:master #45

Merged
merged 2 commits into from
Feb 22, 2025
Merged
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
45 changes: 17 additions & 28 deletions custom_components/localtuya/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -556,39 +556,28 @@ def _dispatch_status(self):
signal = f"localtuya_{self._device_config.id}"
dispatcher_send(self.hass, signal, self._status)

def _handle_event(self, old_status: dict, new_status: dict, deviceID=None):
def _handle_event(self, old_status: dict, new_status: dict):
"""Handle events in HA when devices updated."""

def fire_event(event, data: dict):
event_data = {CONF_DEVICE_ID: deviceID or self._device_config.id}
event_data.update(data.copy())
# Send an event with status, The default length of event without data is 2.
"""Fire events."""
event_data = {CONF_DEVICE_ID: self.id, **data}
if len(event_data) > 1:
self.hass.bus.async_fire(f"localtuya_{event}", event_data)

event = "states_update"
device_triggered = "device_triggered"
device_dp_triggered = "device_dp_triggered"

# Device Initializing. if not old_states.
# States update event.
if old_status and old_status != new_status:
data = {"old_states": old_status, "new_states": new_status}
fire_event(event, data)

# Device triggered event.
if old_status and new_status is not None:
event = device_triggered
data = {"states": new_status}
fire_event(event, data)

if self._interface is not None:
if len(self._interface.dispatched_dps) == 1:
event = device_dp_triggered
dpid_trigger = list(self._interface.dispatched_dps)[0]
dpid_value = self._interface.dispatched_dps.get(dpid_trigger)
data = {"dp": dpid_trigger, "value": dpid_value}
fire_event(event, data)
event_status_update = "status_update"
event_device_dp_triggered = "device_dp_triggered"

if self._interface and old_status and new_status:
# A massive number of events that can be triggered when some devices update too quickly such as temp sensors,
# - We want only to update if status changed except for 1 DP trigger, for scene controls.
if len(self._interface.dispatched_dps) == 1:
dp, value = next(iter(self._interface.dispatched_dps.items()))
data = {"dp": dp, "value": value}
fire_event(event_device_dp_triggered, data)
if old_status != new_status:
data = {"old_status": old_status, "new_status": new_status}
fire_event(event_status_update, data)

def _get_gateway(self):
"""Return the gateway device of this sub device."""
Expand All @@ -611,8 +600,8 @@ def status_updated(self, status: dict):
if self._fake_gateway:
# Fake gateways are only used to pass commands no need to update status.
return
self._last_update_time = int(time.monotonic())

self._last_update_time = int(time.monotonic())
self._handle_event(self._status, status)
self._status.update(status)
self._dispatch_status()
Expand Down
2 changes: 1 addition & 1 deletion documentation/docs/faq/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
A device that has [Low Power Mode](https://developer.tuya.com/en/docs/iot-device-dev/Low_consumption_Wi_Fi?id=Kay3gha1um42e){target="_blank"}, applied on such as __`Wi-Fi door locks and sensors`__. <br>
The device will report its status every x minutes. Most of the time, the device will go into sleep mode, and most likely it will disconnect from the network.
Some Device has an option to control the reports period.
In order to add this device, you need to specify the device sleep time in the [device configartion](../usage/configure_add_device). <br>
In order to add this device, you need to specify the device sleep time in the [device configartion](../usage/configure_add_device.md). <br>
!!! tip ""
If you add the device while it's sleeping and it's `disconnected` from the network, it won't connect <br>
If you changed any value on the device while it is asleep, the new states will be applied when it wakes up. <br>
Expand Down
45 changes: 21 additions & 24 deletions documentation/docs/ha_events.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,28 @@ Localtuya fires an [events](https://www.home-assistant.io/docs/configuration/eve
that can be used on automation or monitoring your device behaviour from [Developer tools -> events](https://my.home-assistant.io/redirect/developer_events/){target="_blank"} (1)<Br>
{.annotate}

1. to monitor your device subscribe to any event below and trigger action on the device
1. to monitor your device subscribe to any event below and trigger action on the device using tuya app


!!! annotate tip ""
With this you can automate devices such as `scene remote` (1) to trigger an action on `homeassistant`


1. e.g. `single click`, `double click` or `hold`.

| Event | Data
| --------------------------------- | ------------------------------------
| `localtuya_device_triggered` | `#!json {"data": {"device_id", "states"} }`
| `localtuya_status_update` | `#!json {"data": {"device_id", "old_status", "new_status"} }`
| `localtuya_device_dp_triggered` | `#!json {"data": {"device_id", "dp", "value"} }`
| `localtuya_states_update` | `#!json {"data": {"device_id", "old_states", "new_states"} }`

Examples
=== "localtuya_device_triggered"

```yaml
Examples
=== "localtuya_states_update"

```yaml title=""
# This will only triggeres if status changed.
trigger:
- platform: event
event_type: localtuya_device_triggered
event_type: localtuya_status_update
condition: []
action:
- service: persistent_notification.create
Expand All @@ -40,7 +39,7 @@ Examples
=== "localtuya_device_dp_triggered"

```yaml title=""

# This will always triggeres if DP used.
trigger:
- platform: event
event_type: localtuya_device_dp_triggered
Expand All @@ -51,7 +50,7 @@ Examples
message: "{{ trigger.event.data }}"

```
???+ example "Automation for scene remote trigger if 1st button single clicked"
??? example "example of an automation to trigger a scene when the first button on a remote is single-clicked"
```yaml title=""

trigger:
Expand All @@ -69,17 +68,15 @@ Examples

```

=== "localtuya_states_update"

```yaml title=""

trigger:
- platform: event
event_type: localtuya_states_update
condition: []
action:
- service: persistent_notification.create
data:
message: "{{ trigger.event.data }}"

```
!!! annotate warning "Database flooding"
If the recorder is enabled, devices like temperature sensors may update frequently (e.g., every second).
This can cause excessive events and significantly increase database size.
It is recommended to exclude _localtuya_ events from the recorder to prevent database overload.
!!! annotate tip ""
```yaml title=""
recorder:
exclude:
event_types:
- localtuya_status_update
- localtuya_device_dp_triggered
```
17 changes: 15 additions & 2 deletions documentation/docs/ha_services.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@

| Service | Data | Description
| ----------- | ---------------------------------------------------------|-------------------------------------
| `localtuya.reload` | | Reload All `localtuya` entries
| `localtuya.set_dp` | `#!json {"data": {"device_id", "dp", "value"}}` | Set new value for one `DP` or multi
| `localtuya.reload` | | Reload All `localtuya` entries
| `localtuya.set_dp` | `#!json {"data": {"device_id", "dp", "value"}}` | Set new value for one `DP` or multi
| `localtuya.remote_add_code` | `#!json {"data": {"target", "device_name", "command_name", "base64", "head", "key" }}` | Manually add code into remote device.


=== "Set DP Service"
Expand Down Expand Up @@ -37,3 +38,15 @@
```yaml
service: localtuya.reload
```

=== "Add Remote Code"
Add a TV button using `head/key` or `base64`
```yaml
action: localtuya.remote_add_code
data:
target: c187a2102cb1e38161377eb4d4afb6f7
device_name: TV
command_name: volume_up
head: "11111111111" # Head: Can be obtain from Tuya IoT device debug logs.
key: "223123" # Key: Can be obtain from Tuya IoT device debug logs.
```
4 changes: 2 additions & 2 deletions documentation/docs/usage/configure_add_device.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Go to hub `Configure` (1) a menu will show up (2) Choose `Add new device`
Used when a device doesn't respond to any Tuya commands after a power cycle, but can be connected to (zombie state). This scenario mostly occurs when the device is blocked from accessing the internet. The DPids will vary between devices, but typically "18,19,20" is used. If the wrong entries are added here, then the device may not come out of the zombie state. Typically only sensor DPIDs entered here.

??? info "(optional) Device Sleep Time"
Only needed if the device has low-power mode and is disconnected from the network. [FAQ](/faq/) <br>
Only needed if the device has low-power mode and is disconnected from the network. [FAQ](../faq/index.md) <br>
If the device is disconnected and exceeds this time, it will be considered offline


Expand Down Expand Up @@ -140,7 +140,7 @@ Each platform has its unique configuration page with different sets of configura
##### Create templates
There are two ways to create templates

1. Export a configured device from the [Reconfigure existing device](../configure_edit_device) step
1. Export a configured device from the [Reconfigure existing device](configure_edit_device.md) step
2. Manually write the configuration __`YAML`__ file `Not Recommended`

??? example "`Cover` template example"
Expand Down
Loading