erijo / tellcore-py

Python wrapper for Telldus' home automation library Telldus Core
GNU General Public License v3.0
44 stars 6 forks source link

raw_event function interfere with lamp commands (on/off/dim) #6

Closed Znarkus closed 8 years ago

Znarkus commented 8 years ago

Hi!

Having trouble executing lamp commands (on/off/dim) from inside raw_event. When I loop over core.devices() only the first device executes the command. Seems like it doesn't wait for the first command to finish.

If I put a sleep after the command it works, but that means slower lamp commands.

I've tried different ways to work around this problem, including using the queue to async the command execution, but that didn't solve it for me.

I'm a python rookie, so I might be doing some mistakes.

The code belows monitor lamp triggers to execute custom functions, such as restoring previous lamp state or simple turning off all lamps.

#!/usr/bin/env python

import re
import tellcore.telldus as td

config = {
    'transmitters': [
        {'house': 15323014, 'unit': 11}
    ]
}

def raw_event(data, controller_id, cid):
    string = "[RAW] {0} <- {1}".format(controller_id, data)
    print(string)

    for transmitter in config['transmitters']:
        m = re.search('house:(\d+);unit:(\d+);group:\d+;method:turn(.+);', data)

        if m:
            # MATCH WITH CONFIG
            house, unit, status = int(m.group(1)), int(m.group(2)), m.group(3)
            print(house, unit, status)

            if house == transmitter['house'] and unit == transmitter['unit']:
                print('MATCH!!!!')
                for device in core.devices():
                    if status == 'on':
                        device.turn_on()
                    else:
                        device.turn_off()

try:
    import asyncio
    loop = asyncio.get_event_loop()
    dispatcher = td.AsyncioCallbackDispatcher(loop)
except ImportError:
    loop = None
    dispatcher = td.QueuedCallbackDispatcher()

core = td.TelldusCore(callback_dispatcher=dispatcher)
callbacks = [core.register_raw_device_event(raw_event)]

# TEST THAT DEVICES WORK
for device in core.devices():
    device.turn_on()

for device in core.devices():
    device.turn_off()

try:
    if loop:
        loop.run_forever()
    else:
        import time
        while True:
            core.callback_dispatcher.process_pending_callbacks()
            time.sleep(0.5)
except KeyboardInterrupt:
    pass
erijo commented 8 years ago

Does the simple loop below work as expected for you?

for device in core.devices():
    device.turn_on()

If not then I would guess that it is a limitation in the protocol.

Znarkus commented 8 years ago

Works perfectly

Znarkus commented 8 years ago

The problem only arises when I use raw events. Code without the raw event handlar works fine. It's like the handler interrupts the lamp commands somehow.

erijo commented 8 years ago

Which python version do you use?

Znarkus commented 8 years ago

I'm pretty sure it's 3.4.1, but I'll double check tonight. I've tried both AsyncioCallbackDispatcher and QueuedCallbackDispatcher.

When it doesn't work properly, the turn_on / turn_off / dim functions return immediately, without waiting for the command to execute. Of the three devices I have, only one is controlled when it behaves like that.

This behaviour only occurs when I trigger lamps from within the raw_event. Otherwise it works – I also have an API server written with Bottle that trigger lamps.

I'm currently using raw_event to catch button presses from my Nexa LWST-615 – maybe there are better ways to do that? :)

erijo commented 8 years ago

Try wrapping the command inside try except and print the error if you get any.

Also, if you could run the command under strace and post the log that would be useful (something like strace -f -tt -o strace.log -s 256 python3 path/to/script).

I can't see that it would make any difference, but you could try adding the transmitter as a device and then listen on device events instead of raw. It would at least save you some parsing.

You could also add the devices you want to turn on/off to a device group and just turn on/off that group.

Znarkus commented 8 years ago

Happy new year :)

Changed how my code waits for threads to finish, and now this suddenly seems to be working. Thanks for all your help and tips!