I’ve been struggling with some Tuya motion sensors I purchased from aliexpress since the last 3-4 days. It was disappointing that HA did not support them, nor did python-tuya or even codetheweb’s tuyapi, I tried the following different ways of getting tuya motion sensor state to HA:
Approach 1: tuya IFTTT integration (failed)
Setup a incoming webhook from IFTTT on motion sensor alarm (sadly there’s no trigger for motion sensor “normal”), and then the following automation, which did two things: turn on an input_boolean and update an input_datetime to capture the last motion timestamp:
alias: IFTTT incoming webhook for tuya motion sensors
description: ''
trigger:
- event_data:
action: motion_sensor_trigger
event_type: ifttt_webhook_received
platform: event
condition:
- condition: template
value_template: '{{ trigger.event.data.sensor != '''' }}'
action:
- data_template:
datetime: '{{ now().strftime(''%Y-%m-%d %H:%M:%S'') }}'
entity_id: input_datetime.{{ trigger.event.data.sensor | replace(" ","_") |
lower }}_last_motion
service: input_datetime.set_datetime
- data_template:
entity_id: input_boolean.{{ trigger.event.data.sensor | replace(" ","_") | lower
}}_state
service: input_boolean.turn_on
Here’s the IFTTT trigger payload:
{ "action": "motion_sensor_trigger", "sensor": "<<<{{DeviceName}}>>>" }
The problem with this: The IFTTT trigger is unreliable. My first automation did not have the trigger.event.data.sensor != ''''
check. IFTTT would send triggers every 30 minutes even when there was no motion detected by the PIR! I then noticed that the correct triggers had the DeviceName
field populated so started checking for that. Then it got worse: it would sometimes not send the DeviceName
even for genuine motion alarms!
The above automation was to switch the input_boolean to ‘ON’, what about switching it ‘OFF’ you may ask. Well that was the job of another automation:
alias: Living Room Motion Sensor Off-State Automation
description: ''
trigger:
- platform: template
value_template: '{{ as_timestamp(states.sensor.date_time.last_changed) - state_attr(''input_datetime.living_room_motion_sensor_last_motion'',
''timestamp'') > states(''input_number.motion_sensor_idle_secs'')|int }}'
condition: []
action:
- data: {}
entity_id: input_boolean.living_room_motion_sensor_state
service: input_boolean.turn_off
This used the difference in time between the time sensor and the last updated motion timestamp on the input_datetime. This too had issues of its own as the time sensor doesn’t really tick away in real time and had a lag of 30+ seconds at all times. Nevertheless, that wasn’t the biggest problem and could be ignored. The bigger problem was that: since the IFTTT trigger wouldn’t fire properly, the input_datetime wouldn’t get updated properly and this would always stay off.
Here are the state entities:
input_datetime:
living_room_motion_sensor_last_motion:
name: Living Room Motion Sensor Last Motion
has_date: true
has_time: true
icon: mdi:mdi-motion-sensor
input_boolean:
living_room_motion_sensor_state:
name: Living Room Motion Sensor State
initial: off
icon: mdi:mdi-motion-sensor
Approach 2: Ping binary sensor (works!)
Note: This approach works flawlessly but only with the battery powered ones.
After the above approach failed, I started looking into more interceptive ways of doing this. I ran wireshark on my laptop and filtered it down to the MAC addresses of the motion sensors. Here’s what I saw - these motion sensors keep sleeping all the time and as soon as there’s some motion, they wake up, send ARP requests to find the router, and do the regular DHCP stuff, and then fire the MQTT message (i believe) to tuya cloud for motion. One way would have been to use something like GitHub - KimiNewt/pyshark: Python wrapper for tshark, allowing python packet parsing using wireshark dissectors and sniff these requests off the network to create a binary sensor. However I found a much simpler way
ping 192.168.1.21
PING 192.168.1.21 (192.168.1.21): 56 data bytes
Request timeout for icmp_seq 0
Request timeout for icmp_seq 1
Request timeout for icmp_seq 2
Request timeout for icmp_seq 3
64 bytes from 192.168.1.21: icmp_seq=13 ttl=255 time=404.428 ms
64 bytes from 192.168.1.21: icmp_seq=14 ttl=255 time=188.593 ms
64 bytes from 192.168.1.21: icmp_seq=15 ttl=255 time=6.086 ms
Request timeout for icmp_seq 16
Request timeout for icmp_seq 17
Request timeout for icmp_seq 18
Request timeout for icmp_seq 19
Request timeout for icmp_seq 20
Request timeout for icmp_seq 21
You see, these sneaky little things come online for around 2-3 seconds before vanishing away. In that small little window, they do respond ping/ICMP requests! Bam, and here’s the solution:
binary_sensor:
- platform: ping
host: 192.168.1.21
count: 1
scan_interval: 1
name: ping_tuya_motion_sensor_master_bedroom
- platform: template
sensors:
tuya_motion_sensor_master_bedroom:
friendly_name: "Master Bedroom Motion Sensor Alarm"
value_template: >-
{{ as_timestamp(states.sensor.date_time.last_changed) - as_timestamp(states.binary_sensor.ping_tuya_motion_sensor_master_bedroom.last_changed) < states('input_number.motion_sensor_idle_secs')|int }}
That’s it. You now have a working binary sensor which accurately represents your Tuya motion sensor state. The first binary sensor does the actual work. It uses the ping platform with the lowest interval of 1 seconds (because these sneaky things disappear quickly after waking up). And booyah:
The second, template binary sensor, then creates the illusion of motion being detected for a while and then turning to an off state based on an input_number of idle seconds. I believe even the Tuya cloud would be doing the same as the sensor doesn’t really wake up to tell the cloud when motion is no longer detected. You can ofcourse configure idle seconds to your liking (mine is set to 10 minutes or 600 seconds).
Here’s the end result:
There’s a tiny problem right now which can be easily solved: i enabled the debug logs and saw that the ping sensor isn’t really pinging at my configured interval of 1 seconds, but 3 seconds (and exactly every 3 seconds for some reason), so it misses the motion sensor sometimes. I intend to write a simpler ping sensor which can just do a simple continuous ping and report back state that way (instead of waking up on intervals and doing pings).
Hope this helps somebody like me, who does not have the equipment or doesn’t want to risk flashing their sensors with Tasmota and such to get them working with HA.