mknx / smarthome

http://mknx.github.io/smarthome/
GNU General Public License v3.0
126 stars 68 forks source link

Russound Plugin #3

Closed 2ndsky closed 11 years ago

2ndsky commented 12 years ago

I checked in a new plugin to control a russound multiroom audio device which is still under development. I copied the structure from the squeez plugin. The target is, that the plugin will communicate with the russound over a rs232 connection but I don't know how to achieve that yet. Have to read some tutorials how to talk to a socat socket. So this one is not tested yet.

mknx commented 12 years ago

you could have a look at the dmx plugin, it uses a serial interface. Or have a look at the asterisk plugin and using asynchat for a robust tcp connection. Why want you to fiddle with socat? Because it is the wiregate answer to every serial communication?

2ndsky commented 12 years ago

I only want to use the socat way because of the wiregate threads about problems talking with the serial port. If you say there is a better or another way which also works I will try it (I'll have a look on the mentioned plugins). My last serial communication was implemented in C over ten years ago ;)

Thanks for the hint!

mknx commented 12 years ago

You are not enslaved from perl anymore. Free your mind ;-) Happy hacking.

2ndsky commented 12 years ago

Hi Marcus, I looked at the dmx and the asterisk plugin. The way it works with dmx is not the way I could speek with the russound because the communication is event based. I'd like to switch the russound in event mode so that it tells me if its state has changed for example over the iOS App. To use the serial port like the dmx plugin does I have to implement threading which I want to avoid. The asynchat looks pretty but do you know a way to use it with serial communication instead of TCP? I could connect via TCP to the russsound too but heard about problems when the russound is idle that it randomly send its ethernet port to standby and not reacting to commands anymore. So using the serial port is the prefered way. Any hints on that?

UPDATE: what do you think about twisted (http://twistedmatrix.com/trac/)? MIT license should be fine for us, isn't it?

mknx commented 12 years ago

I think you could combine the python serial package with asynchat. You have to overlay some functions of asynchat with the serial read/write functions. I'm on the road for two days, [update] so I could not write a prototype and I really want to release 0.7.[/update] My opinion about twisted: this is a huge beast. Does is provide the needed serial communication feature?

2ndsky commented 12 years ago

Yes, it does but you're right with the huge beast. I'll do further reading on that and see if I can subclass asynchat for my purposes.

2ndsky commented 12 years ago

Could you please take a look at this post when you're back in town and tell me your opinion: https://sourceforge.net/tracker/index.php?func=detail&aid=3559321&group_id=46487&atid=446305

Update: found another promising library plib: http://pypi.python.org/pypi/plib/0.8.1 The advantage here is that you can easily switch between TCP and serial communication without changing your code much. This is a very interesting thing for the russound because you can talk RIO over TCP or serial but serial seems to be more stable than the etnernet interface. But for people who don't want to use the RS232 stuff, they can try it with the TCP connection.

mknx commented 12 years ago

The SF post looks promising. I thought it is easy, now I know it's easy. I think this is the best was to go. Switching between RS232 and TCP is just a few lines of code. The benefit would be that we don't need a separate thread for this plugin and the user doesn't have to install the plib package.

Two notes on your code: L47-: The configuration of the plugin should be in the plugin.conf. Settings like serial/TCP.... The zones could be described in the items/*.conf and the parse_item function. Smth. like rs_zone = foo L56: you should use if item.return_parent() in

I'm really looking forward for your finished plugin. If I could help don't hesitate to ask.

2ndsky commented 11 years ago

I made a complete reimplementation so that any item can be russound parameter. Now there is no need for a specific item structure. I've not tested this commit yet, but can you please take a look at the source code and tell me your opinion?

mknx commented 11 years ago

It looks promising! Nice and clean.

I've added a few comments to the commit: https://github.com/mknx/smarthome/commit/399056eb5743e1745dd7fd8dd1f490aa84914d48#L0L94

Do you have an example configuration?

2ndsky commented 11 years ago

I'll create one when I have tested the plugin. I'm a little bit busy at the moment. Maybe I have time on the weekend for that.

2ndsky commented 11 years ago

Hello Marcus, I know its difficult for you to debug but maybe you can see the problem in code. The connect seems to work properly and I get no errors on sending the watch command but the parse respond never get called. If I connect to the russound using telnet I get the right answer. Any ideas?

mknx commented 11 years ago

Hi, I would put the content of the run function into a function called handle_connect. This function will be called on every (re)connection. See the knx plugin for an example.

Furthermore you could create a function to dump the incoming data to stdout.

def collect_incoming_data(self, data):
    print data
    self.buffer += data

Do you see anything?

2ndsky commented 11 years ago

Plugin works on my dev machine like a charm now. I'll test it the next few days a little further and then we can merge it to the master branch if you agree. And here the promissed sample configuration for one zone:

['dg']
        [['schlafen']]
                [[['audio']]]
                        [[[['status']]]]
                                type=bool
                                rus_path=1.1.status
                        [[[['volume']]]]
                                type=num
                                rus_path=1.1.volume
                        [[[['bass']]]]
                                type=num
                                rus_path=1.1.bass
                        [[[['treble']]]]
                                type=num
                                rus_path=1.1.treble
                        [[[['balance']]]]
                                type=num
                                rus_path=1.1.balance
                        [[[['turnonvolume']]]]
                                type=num
                                rus_path=1.1.turnonvolume
                        [[[['source']]]]
                                type=num
                                rus_path=1.1.currentsource
                        [[[['mute']]]]
                                type=bool
                                rus_path=1.1.mute
                        [[[['loudness']]]]
                                type=bool
                                rus_path=1.1.loudness
                        [[[['partymode']]]]
                                type=str
                                rus_path=1.1.partymode
                        [[[['donotdisturb']]]]
                                type=str
                                rus_path=1.1.donotdisturb

If it is merged into the master branch I will test it on my production machine in combination with the knx plugin and will give you a example of that, too.

mknx commented 11 years ago

congratulations to the first working plugin! Nice.

I couldn't see a real bugfix in your latest commit. Have you had a configuration error?

2ndsky commented 11 years ago

Thank you very much. Oh the latest commit of the russound plugin did have some bugfixes. The command was not put to lowercase in some cases and the zone watch was executed for each config item even if the watch command was already executed for the same controller and zone on another config item.

2ndsky commented 11 years ago

Okay, there is still another bug anywhere. After two hours of running the plugin sends only 'OFF' which seems to end in a communication loop. Maybe the russound switch to standby and closes the connection. If I see it correctly the problem is in the handle_close. I out commented the code there and give it another try today.

2ndsky commented 11 years ago

Without the calls to remove the zone and system watch in the handle_close the loop is gone and smarthome.py reacts on a telnet login (which it didn't before when the loop occures). But if I try to talk to the russound after two hours (maybe the timeout for the russound when no zone is turned on) I get no answer and changes to the russound using the iphone app are not reflected back to smarthome.py. I assume that it lost connection and didn't recognized this. Should not the monitor recognize this and do a reconnect? Another possibility could be to activly try a reconnect if the russound is not answering a request immediatly.

Any ideas from your side?

P.S.: that problem seems to be solved if we use the serial connection but the ethernet way is a lot easier than using an extra usb to serial converter with another cable through the network rack so that get this up and running will be the prefered way for me.

mknx commented 11 years ago

Could you please update the russound branch, so I can have a look at the current code.

The handle_close could only be used for a local cleanup. You couldn't send data over the connection anymore. It's already closed. The handle_close of my_asynchat sets self.is_connected = False which triggers the connection monitor to try a new connection.

And what do you mean with "the plugin sends only OFF". Does the russound send this?

P.S. I'm not a friend of a bunch of serial to usb converters as well. If this thing provides a ethernet port we should use it.

2ndsky commented 11 years ago

I've pushed the current version of my plugin without the handle_close methode because I missunderstood its meaning. For my plugin there is no need for a local cleanup. In the old version I tried to send a zone watch off command. I think because of a bug on my string concatanation it only sends 'OFF' and not the whole string. But If there is no connection anymore at that time I can avoid sending this to the russound.

The problem seems to be that the russound kills the connection after two hours of inactivity when no zone is on. Other users reported that this isn't the same with the serial port. Connections on that stay open. At this point I try to figure out, if the connection monitor recognize this closed connection and we have a problem at the reconnect or if the monitor just don't get it.

A quick workaround could be to do something like a ping at least every hour to keep the connection open or to check the response of the russound after a request and if no one comes in then try to reopen the connection. The first option looks like a hack to me and the later is not implementable in a beautiful manner.

2ndsky commented 11 years ago

Another thing: I looked at the my_asynchat and the handle_close method. Now I understand what you wrote above. How is it with python, if I overwrite the handle_close method in my plugin is the super class method called anyway or do I have to explicitly call it in my overwritten method? Maybe this could be the problem, that I overwrite the method and not set the self.is_connected to False so that the connection montior doesn't recognize the closed connection. I'll give it another try without the handle_close method overwritten.

2ndsky commented 11 years ago

Great, I tested the code without the handle_close method so that it seems that the original one from the my_asynchat does its job and voila as connection times out its reopened by the connection monitor. Really nice!

mknx commented 11 years ago

Still running?

And yes you have to call the method of the base class if you define a method with the same name in the derived class. See http://docs.python.org/tutorial/classes.html#inheritance

2ndsky commented 11 years ago

Yes, still running on my test machine with reconnect every two hours. If it still runs tomorrow I'll merge it to the master branch and test it more deeply with the knx integration on my production machine.

mknx commented 11 years ago

before you merge it into master, please remove the other plugins which are in development (dwd, rrd, squeeze).

mknx commented 11 years ago

two comments on your code:

2ndsky commented 11 years ago

Hopefully I've pushed it the right way this time. Should now be merged in the master branch.

mknx commented 11 years ago

Now part of the master branch and the upcoming 0.8 Release.