TCP/UDP Bindings State vs. Command

Hi.

I’ve got a rs485 to TCP/IP bridge that I’m using to connect to a Philips Dynalite network. The bindings themselves work a treat, it’s simply two strings; one for sending and one for receiving:

String IO_Dynet_Send "[%s]" { udp=">[192.168.10.250:1000:'REGEX((.*))']" }
String IO_Dynet_Receive "[%s]" { udp="<[192.168.10.250:*:'REGEX((.*))']" }

There’s an extra udp:port line in openhag.cfg for incoming packets as well, and as it is I can run IO_Dynet_Send.sendCommand (“blah”) to send commands onto the Dynalite network without a problem. Similarly, I can see incoming messages arrive on IO_Dynet_Receive and create a rule to process them; sort of.

Incoming messages are treated as states and not commands. That means when I receive a lot of messages, some may be missed as I have to read IO_Dynet_Receive.state, which might’ve been updated again by the time that line of code executes from a previous update.

The Dynet network contains all the wall panels around the house (light switches) and the controllers (relays and dimmers) for the lighting, so messages contain both state and command information (eg, area 5, button 1 ON/RAMPUP/RAMPDOWN) or state information (area 5, down lights level 60%).

These messages arrive as strings, in the form of 8 hex pairs, space separated, for an 8 byte message. For exammple it may read “5C AA 55 01 05 00 00 9F”. The plan was to create a rule for “IO_Dynet_Received received command”, and then process the receivedCommand implicit variable in that rule, which is I can then easily process by splitting that string into an array, using parseInt on base 16 and then a very short tree of bitwise operations.

Is there a way I can configure the IO_Dynet_Binding to treat incoming UDP packets as commands and not states? The MQTT binding actually has a setting for that in the binding itself. I don’t want to configure a whole bunch of individual Switch items for every single button and use very specific REGEX transforms to match.

Alex.

@watou can probably confirm this (I think he has been messing around with that part of the code recently) but I suspect that String Items only receive updates, not commands. I bet the same is true for Number and DateTime Items as well.

That being said…

The following is based on experience and more than little bit of supposition so I could be way off base. BUT

When a rule triggers a bunch of time I believe multiple instances of the rule end up executing at the same time in separate threads. So I think the following would work:

  1. Go back to a received update rule trigger
  2. Put a lock around your rule so only one can execute at a time
  3. Rather than using IO_Dynet_Receive.state to get the state, use the receivedCommand implicit variable. NOTE: this is the part that may make this whole thing fall apart if that variable only gets populated for commands as the name implies.

You could create a rule to break up the text and send commands to your Switches. Not sure that helps much but I’m currently not seeing a way around it if my idea above doesn’t pan out.

String items can receive StringType commands. Likewise, Number items can receive DecimalType commands, and DateTime items can receive DateTimeType commands. This would all be worth documenting beyond the code itself! :smile:

Thank you both for the responses.

I’ll try some of these things out. I do know strings can receive commands because I do it with MQTT. Another option might be to just set up a background service that simply reads/writes the socket in and out of MQTT and use that binding. It’s just one extra link in a chain I’d rather not build in the first place.

I’ll have to try the received update with lock, but my suspicion is that the sequence of events is that the state is updated, and then the trigger is called. It’ll stop the same rule running multiple times concurrently, however, the state update happens before so that’ll still be changing in the background. I have tried using receivedCommand in the updated state trigger, and the variable isn’t even there let alone populated. There is a previousState implicit variable. It’d be nice if there’s a newState or something similar as well.

Basically the idea is to create a rule and break up the text, and then send commands to the actual items, or update their states, and then possibly even send commands back out onto Dynet using the outbound binding. That’s the plan at least.

The way the binding works as it is makes sense for most purposes where you’re controlling a remote device (send commands, receive states). For cross connecting two different systems though, both would be needed. Might be a feature request in this somewhere. Chaining in MQTT or something would add a potential delay, which is why I’m avoiding that option for now.

So if I’m understanding what you are seeing and what @watou describes the root problem is that the Serial binding calls postUpdate for String Items rather than sendCommand, right? Otherwise you should be able to trigger the rule on received command instead of received update, and the receivedCommand should be populated with the value of the Item that caused the rule to trigger and the locks should work. Or am I missing something?

UDP binding, not serial, and correct. The two bindings are configured as follows:

String IO_Dynet_Send "[%s]" { udp=">[192.168.10.250:1000:'REGEX((.*))']" }
String IO_Dynet_Receive "[%s]" { udp="<[192.168.10.250:*:'REGEX((.*))']" }

Triggers for received command do not trigger on IO_Dynet_Receive for any data received from the network.

My bindings for MQTT are as follows, where you can see the third parameter is set as “command”, giving me the option of how incoming data is treated. Ideally the TCP/UDP bindings would have exactly the same option.

String IO_GenIII_Send "[%s]" { mqtt=">[home:/serial/geniii/in:command:*:default]"}
String IO_GenIII_Receive "[%s]" { mqtt="<[home:/serial/geniii/out:command:default]"}

Is it true that your problem is not whether the incoming data is an “update” or a “command” but whether you have access to a snapshot of the related data? Are you just wanting to use a command as workaround for not getting a snapshot of the updated state in your rule?

If so, the JSR223 rules provide a snapshot of updated state (both new and previous values) to the rule body. You might want to consider that as an alternative to the rule DSL.

What I need to achieve is simply receiving and processing all messages; how that’s achieved isn’t really important. I am relatively new to openHAB development, Xtend and Java aren’t my strong point either, but that’s never stopped be from trying before.

So if JSR223 rules let me read old and current state values that triggered the current instance of the running rule (given that several could be firing concurrently), then that’d work just fine. I’ve just never heard of them before so time to do some more reading I think. Thanks for the pointer.

All I know is the ordinary rules that I’m working with so far, and that the command event trigger has receivedCommand as an implicit variable, so I know that no matter how fast the commands come, I can read all of them, and using state based triggers does not and I’m forced to read it from the Item variable itself, which may have changed again even if reading the value is the very first thing that I do in the event body. It minimised the chances, but it’s really just a race condition and inelegant.

In an ideal world I’d just take one of the existing bindings and modify it, but too much to learn in too shorter time, and I’m somewhat time starved at the moment. It’s been easier to whip up intermediate Linux daemons in plain old c++ and have them feed in/out of MQTT and then use that binding. I thought I’d try something different and learn something new this time since it’s summer and I have a few days on my hands.

In case it helps. I wrote a tutorial on JSR223 Jython (Python) rules.

That’s what I understood. I don’t know why the rule DSL doesn’t pass along the new item state since it is available in the event received from the OSGI event bus. I also don’t know if the MQTT support for incoming commands (normally outgoing to devices) was a workaround for this issue. If so, I think it would have been better to fix the rule DSL instead. In any case, the DSL change won’t happen at this point given the impending transition to OH2/ESH.

Nice. It’s freezing here (Philadelphia). :slight_smile:

Brilliant that’s perfect, and also gives me some choice. My day job world is mostly .NET and JS (AngularJS, jQuery sort of stuff), and C/C++ in the Unix world. I can’t say that I’ve been enjoying Xtend much, so I have a way out now as a bonus :smile:

Nice. It’s freezing here (Philadelphia). :smile:

Perth (Australia) here, and at this time of year most of the country just turns into Mordor.

The JSR223 binding also supports writing rules in Javascript although I haven’t done that myself.

Hello,

I can send a command through the TCP Bindings and I can get the expected data correctly (verified with Wireshark:

).

Here is my setup:

-> my .cfg:

tcp:port=22222
tcp:postamble=\n
tcp:updatewithresponse=true
tcp:charset=ASCII

-> my .items:

String JavaMeteo "Jav Met [%s]" (gRDC) {tcp=">[172.16.128.112:22222:'REGEX((.*))']"}
String JavaMeteo_receive "Jav Met recev [%s]" (gRDC) {tcp="<[172.16.128.112:*:'REGEX((.*))']"}

-> my .rules:

rule "TEST Davis"
    when 
        Item TESTDavis received command
	then if (receivedCommand==ON){			
        JavaMeteo.sendCommand("LOOP 1")
	Thread::sleep(1000)
		logInfo("TestJS","JS : " + transform("JS", "MeteoVantage.js", JavaMeteo.state.toString))
	}else{		
		JavaMeteo.sendCommand("LAMPS 0")
	Thread::sleep(1000)
		logInfo("TestJS","JS : " + transform("JS", "MeteoVantage.js", JavaMeteo.state.toString))
	}
end

-> MeteoVantage.js

// Wrap everything in a function
(function(i) {    
     return (i)+2;
})(input)
// input variable contains data passed by openhab

-> my result:

Launching the openHAB runtime...
osgi> 2016-06-02 11:39:57.574 [INFO ] [.o.core.internal.CoreActivator] - openHAB runtime has been started (v1.8.2).
2016-06-02 11:39:58.207 [INFO ] [o.o.i.s.i.DiscoveryServiceImpl] - mDNS service has been started
2016-06-02 11:39:58.445 [INFO ] [o.o.i.s.i.DiscoveryServiceImpl] - Service Disco very initialization completed.
2016-06-02 11:39:59.767 [INFO ] [penhab.io.rest.RESTApplication] - Started REST API at /rest
2016-06-02 11:40:08.030 [INFO ] [c.internal.ModelRepositoryImpl] - Loading model 'Maison.sitemap'
2016-06-02 11:40:08.133 [INFO ] [c.internal.ModelRepositoryImpl] - Loading model 'myopenhab.persist'
2016-06-02 11:40:08.177 [INFO ] [c.internal.ModelRepositoryImpl] - Loading model 'Maison.script'
2016-06-02 11:40:08.232 [INFO ] [c.internal.ModelRepositoryImpl] - Loading model 'Maison.items'
2016-06-02 11:40:08.724 [INFO ] [.o.u.w.i.servlet.WebAppServlet] - Started Classic UI at /classicui/openhab.app
2016-06-02 11:40:12.826 [INFO ] [t.AbstractSocketChannelBinding] - The maximum buffer will be set to the default value of 1024
2016-06-02 11:40:12.826 [INFO ] [t.AbstractSocketChannelBinding] - The interval to retry connection setups will be set to the default value of 5
2016-06-02 11:40:12.827 [INFO ] [t.AbstractSocketChannelBinding] - The cron job to reset connections will be set to the default value of 0 0 0 * * ?
2016-06-02 11:40:12.828 [INFO ] [t.AbstractSocketChannelBinding] - The setting to queue write operation until a channel gets connected will be set to the default value of true
2016-06-02 11:40:12.829 [INFO ] [t.AbstractSocketChannelBinding] - The setting to share channels within an Item will be set to the default value of true
2016-06-02 11:40:12.829 [INFO ] [t.AbstractSocketChannelBinding] - The setting to share channels between the items with the same direction will be set to the default value of true
2016-06-02 11:40:12.830 [INFO ] [t.AbstractSocketChannelBinding] - The setting to share channels between directions will be set to the default value of true
2016-06-02 11:40:12.831 [INFO ] [t.AbstractSocketChannelBinding] - The setting to use address masks for incoming connections will be set to the default value of true
2016-06-02 11:40:12.832 [INFO ] [t.AbstractSocketChannelBinding] - The refresh interval of the worker thread will be set to the default value of 250
2016-06-02 11:40:12.833 [INFO ] [t.AbstractSocketChannelBinding] - Listening for incoming connections on /0:0:0:0:0:0:0:0:22222
2016-06-02 11:40:12.836 [INFO ] [.service.AbstractActiveService] - TCP Refresh Service has been started
2016-06-02 11:40:12.836 [INFO ] [t.protocol.internal.TCPBinding] - The maximum time out for blocking write operations will be set to the default vaulue of 3000
2016-06-02 11:40:12.837 [INFO ] [t.protocol.internal.TCPBinding] - The blocking nature of read/write operations will be set to the default vaulue of false
2016-06-02 11:40:12.839 [INFO ] [t.protocol.internal.TCPBinding] - The preamble for all write operations will be set to the default vaulue of ""
2016-06-02 11:40:12.840 [INFO ] [t.AbstractSocketChannelBinding] - Connecting the channel Channel [item=JavaMeteo, command=0, direction=OUT, remote=/172.16.128.112:22222, buffer=, isBlocking=false, isReconnecting=false, channel=, host=172.16.128.112, port=22222]
2016-06-02 11:40:12.841 [WARN ] [t.AbstractSocketChannelBinding] - When using address masks we will not verify if we are already listening to similar incoming connections
2016-06-02 11:40:12.842 [INFO ] [t.AbstractSocketChannelBinding] - We will accept data coming from the remote end 172.16.128.112:*
2016-06-02 11:40:12.860 [INFO ] [.p.rrd4j.internal.RRD4jService] - Removing invalid defintion component = null heartbeat = 0 min/max = 0.0/0.0 step = 0 0 archives(s) = [] 0 items(s) = []
2016-06-02 11:40:13.093 [INFO ] [t.AbstractSocketChannelBinding] - The channel for /172.16.128.112:22222 is now connected
2016-06-02 11:40:18.300 [INFO ] [c.internal.ModelRepositoryImpl] - Loading model 'Maison.rules'
2016-06-02 11:40:27.269 [INFO ] [.myopenhab.internal.MyOHClient] - Connected to my.openHAB service (UUID = 6fe97abb-****-****-****-64b868d097b9, local base URL= http://localhost:8080)
2016-06-02 11:40:42.713 [INFO ] [runtime.busevents             ] - TESTDavis received command ON
2016-06-02 11:40:42.988 [INFO ] [runtime.busevents             ] - JavaMeteo received command LOOP 1
2016-06-02 11:40:42.995 [INFO ] [runtime.busevents             ] - JavaMeteo state updated to LOOP 1
2016-06-02 11:40:43.611 [INFO ] [runtime.busevents             ] - JavaMeteo state updated to LOO
2016-06-02 11:40:44.776 [INFO ] [rg.openhab.model.script.TestJS] - JS : LOO2
2016-06-02 11:40:52.998 [INFO ] [runtime.busevents             ] - TESTDavis received command OFF
2016-06-02 11:40:53.016 [INFO ] [runtime.busevents             ] - JavaMeteo received command LAMPS 0
2016-06-02 11:40:53.017 [INFO ] [runtime.busevents             ] - JavaMeteo state updated to LAMPS 0
2016-06-02 11:40:53.862 [INFO ] [runtime.busevents             ] - JavaMeteo state updated to OK
2016-06-02 11:40:54.070 [INFO ] [rg.openhab.model.script.TestJS] - JS : OK2

However, the return string is displayed instead of the string sent. Furthermore, no element is displayed in the return chain. Why?

Also, how can I extract and then parse the hexadecimal string that comes from my weather station please? Indeed, I wish to extract each element as indicated in the document on page 22: http://www.davisnet.com/support/weather/download/VantageSerialProtocolDocs_v261.pdf

Thank you in advance for your help.

Flavien

Do you have any news on this ?
Maybe somebody had made a real binding for dynalite

Philips has made a network gateway called Envision Gateway, maybe this could be the link between openhab and the dynalite bus

1 Like