Artnet DMX module

Begonnen von zevnik, 17 Januar 2014, 00:54:32

Vorheriges Thema - Nächstes Thema

zevnik

Hi all,

if anyone is interested, I've written a very basic Artnet module for FHEM, which works well with Ulrich Radig's artnet and dmx modules. You can download it from http://code.google.com/p/fhem-artnet/

Now I have two questions:
1. I wanted to control my artnet with homematic wandsender via notify, but for every click I get two notifies in fhem. I solved this with ignoring any commands within 600ms after a successful command received. Is this OK?
2. I want to implement dimming functionality in my module. This means I need to change artnet values at least 25 times per second. I wanted to start a separate thread for this, but my Perl on Synology doesn't support threads. Is there any other recommended way of doing this in fhem?

Thanks.

rudolfkoenig

1. Check the events more carefully, and change the notify regexp, to only match one of them.
2. Try to use InternalTimer, and if it is not enaugh, then BlockingCall

zevnik

#2
@rudolfkoenig: thanks, InternalTimer works as a charm, I always thought, I cannot use it for sth, which needs to be run every 0.04 seconds:)

One more questions. I guess this artnet module might benefit also other users. What all do I need to do, to get it in the main branch?


I need to correct myself: on my synology, this InternalTimer doesnt work fast enough, to dim lights smoothly. Do you think BlockingCall would solve the issue?

rudolfkoenig

I can check it in the contrib directory if you wish.

If the module is documented, and you are ready to support it for some time, then it should be part of the fhem/FHEM directory, which is automatically distributed with the update command. You should send me your sourceforge account in this case, and I'll give you write-permission to the SVN.

rudolfkoenig

ZitatDo you think BlockingCall would solve the issue?

Not sure about it. BlockingCall creates a separate process, so "longrunning" notifies/modules wouldn't block your task. OTOH it may be that you simply cannot execute your code 25 times per second on the Synology, and you either have to optimize it, or choose a faster/compiled language.

There is an apptime command which may help you in searching for the bottleneck.

zevnik

Hi,

I've just redone it for blocking call and now dimming works on synology too, it is fast enough, it manages to refresh data also with 50Hz. Thank you for your help.

I'd like to contribute sth back to the community, so yes, I am willing to support the module, and if possible, get your feedback regarding the documentation and coding style.

File can be found here: http://code.google.com/p/fhem-artnet/source/browse/trunk/20_ARTNET.pm




rudolfkoenig

Please send me your sourcefource account.

Some feedback to your module:
- presetting attributes by a module is wrong: the user should have the ability to leave them empty, and the default value should be specified in the module in the AttrVal() call.
- setting attributes in Initialize is doubly wrong: attributes belong to an instance, and not (yet?) to a module, in Initialize you do not have the name of the instance.
- setting attributes in NotifyFn is even more wrong: the user has no chance in ever changing it.
- by setting $hash->{NOTIFYDEV} in DefineFn to global you will be only called for global changes (this is a new feature to avoid unnecessary calls).
- DefineFn: did I mention that setting attributes by the module is wrong?
- GetFn is not yet finished, and CUL should be changed.
- when returning the set/get error message, you can specify optional widgets (dropdown/slider/etc) for FHEMWEB, see http://fhem.de/commandref.html#webCmd for details

zevnik

Thank you for your feedback, so basically I just need to stay away from setting attributes everywhere:)

One more question. I would like to redo artnet so that it will consist of two parts, artnet (as iodevice) and artnet_fixture as a light or other device connected via this ioidevice.

I've defined these in artnet:
# Provider
$hash->{ReadFn}  = "ARTNET_Read";
$hash->{WriteFn}  = "ARTNET_Write";
  $hash->{Clients} = ":ARTNET_FIXTURE:";


and in fixtures i call
ZitatAssignIoPort($hash);

but I can't seem to find, how to communicate between modules (when calling set function in fixture, how does this get transfered to artnet write function).

thanks.

rudolfkoenig

The FHEM two-level model:

- the physical module opens the device, and its ReadFn is called after the global select reports, that data is available.
- on Windows select does not work for devices not connected via TCP, here is a ReadyFn function necessary, which polls the device 10 times a second, and returns true if data is available.
- ReadFn makes sure, that a message is complete and correct, and calls the global Dispatch() with one message
- Dispatch() searches for a matching logical module (by checking $hash->{Clients} or $hash->{MatchList} in the physical module, and $hash->{Match} in all matching logical modules), and calls the ParseFn of the logical module
- ParseFn parses the data, sets all readings via the readings*Update functions, and returns the name of the logical device. When the readings*Update functions are called by ParseFn called by Dispatch, no event triggering is done, contrary to calling them directly (without Dispatch on the call stack).
- Dispatch triggers the event-handling for the device returned by ParseFn.

The IODev entry (assigned by AssignIoPort) is only relevant when sending messages, and is evaluated by the IOWrite call, which should be used in the logical device. This is the other way (logical -> physical).

If there is no direct communication between the logical and the physical module (e.g. calling functions directly, checking $hash entries, etc), then you can stack modules (e.g. for routers like RFR) or use FHEM2FHEM:RAW to connect two FHEM installations.

zevnik

Rudolf hi,

after the flu and other processes I am back at working on the artnet module.
And I have one further question:
-I have one physical module which connects to artnet and has all the channel states available,
-then I have logical modules which controll the states of channels on physical module
--one logical module will be RGB (so I can use RGB color picker)
--other module is plain dimmer.

Both of these logical modules are using basically the same functions, they differ only in some definitions. How do I make an "abstract" module, which is then extended by these specific implementations? One idea is to have this "common methods" available in physical module.

Is there a similar implementation already somewhere in the code?

rudolfkoenig

ZitatOne idea is to have this "common methods" available in physical module.
Go ahead, this sounds reasonable.

ZitatIs there a similar implementation already somewhere in the code?
Not that I am aware of.

Try to avoid calling functions beside "Dispatch()" and "IOWrite()" for communication between the logical and the physical module, else you loose the ability to use FHEM2FHEM in RAW mode with autocreate and set ability.
Data from Dispatch() called by the physical module is passed to the ParseFn() of the logical module, and data from IOWrite() called by the logical module is passed to the WriteFn() of the phyiscal module.

justme1968

i'm not sure if this is what you mean by similar but maybe a look at the withings, netatmo, swap and hue modules gives you a few ideas that are applicable to your concept also.

the whitings and netatmo modules operate each in 3 different modes where one is the 'physical' and the others are the 'logical' module level. and they share a lot of code.

the swap module can be extender by more specialized swap modules that will overwrite parts of the module hash in the initialize function but reuse nearly all of the define, parse and dispatch code and extend the set and get functions with callbacks that are called from the general swap module.

one more option is to use only one module for your two clients and have a model or subtype attribute to switch between the colorpcker and dimmer incarnations. in the hue module a subtype of switch, dimmer or colordimmer switches the behavior of the device between a simple on/off switch a 1 channel dimmer and the full color enabled version.
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

zevnik

@justme1968: great. I totaly forgot about subType. That's what I am implementing.

But currently I am stuck with dispatch from physical module.
I am dispatching within SetFn (since artnet isn't returning its state):

#ARTNET_FIXTURE - logical client
sub ARTNET_FIXTURE_Parse($$) {
my ( $hash, $msg ) = @_;

Log3 undef, 3, "Got msg " . $msg;

my @ret = (0);
return @ret;
}



#ARTNET - physical master
my %addvals;
my $msg = "ARTNET " . $state;
Dispatch($hash, $msg, \%addvals); # we send message to our logical devices


Problems I have with dispatch:
- I keep getting "artnet: Unknown code ARTNET 1414170000, help me!" (ARTNET 1414170000 is message I am sending)
- which means my artnet cannot find clients, I tried setting $hash->{Clients} = ":ARTNET_FIXTURE:" without success,
- by manually setting my $shash = $defs{'argb'} dispatch gets to ARTNET_FIXTURE but it produces the same error (help me!)
- from the code I think it is checking the return value from parse call (!int(@ret)), but I believe it never even comes to the code, since I don't get anything in my log.

Any help is appreciated :)

justme1968

if the parse function did accept a dispatched message it should return a bin empty list with the devices the message was intendet for. then the dispatch loop over all devices will succesfully stop.
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

zevnik

I am little fresh with perl&fhem, so I apologize for beeing noob.

1. how do I tell ARTNET which clients are bound to it (there can be multiple ARTNET devices, so probobaly when FIXTURE connects, it should fill ARTNET->{Clients} list with something, but with what?).
2. then ARTNET sends Dispatch(self, "message", <unknown parameter?>),
3. dispatch goes through ARTNET->{Clients} and calls ParseFn function of FIXTURE
4. and then FIXTURE's ParseFn should return bin empty list? so it should return "@ret = (); return @ret" ?

I think I am missing something very obvious, or just still too fresh with fhem.