Hi programing Guru’s
Where can I find the Luup command to do a TCPIP connection? Get command?
I am writing a plugin to query a TCPIP Modbus module for temperature logging…any help is much appreciated!
I need to send raw hex data out…is there an example anywhere that shows the format sequence to do this in Luup code?
Thanks
Tim
Looking at the Luup Lua extensions…
I am thinking that the function: wget is for HTTP communication…?
To establish a TCPIP connection and then send data is the Module: io…open, then write used?
Sorry for the stupid questions…I learned other languages so the terminology is different and throwing me off!
Thanks for your help…
Tim Alls
The raw TCP commands are party of a Lua library called LuaSocket. LuaSocket has a home page but it lacks somewhat in simple examples and it assumes you already know how to do socket programming in C. I usually have to find an existing example and modify it.
(Edit: spelling)
Thanks,
If you have any links to the use of the Socket Library let me know…I will start looking for one as well.
Tim
Is this correct for sending binary data out on a TCPIP connection?
local socket = require(“socket”)
host = “192.168.1.202”
c = assert(socket.connect(host, 502))
c:send(0,0,0,0,0,6,1,4,0,0,0,8)
c:close()
Let me know!
Next is to read the data from the Modbus Slave and process the data…
Thanks for any help on this one.
Regards
Tim Alls
Dunno, it could be. Try it and see. It looks syntactically valid to my Compiler In My Head. Whether it does what you intended is going to require testing.
Tim,
[tt]send()[/tt] takes a [tt]string[/tt] argument, so you’ll need to do something akin to:
c:send(string.char(0,0,0,0,0,6,1,4,0,0,0,8))
which will convert the binary into a string so you can pump it through [tt]send(…)[/tt]
You’ll see this in IORelay plugin when I need to send binary data:
http://code.mios.com/trac/mios_iorelay/browser/trunk/L_IORelay1.lua#L124
NOTE: You may not be able to print that string out, to [tt]luup.log()[/tt] etc, since it may not translate correctly to the underlying OS character set…
[quote=“guessed, post:7, topic:170475”]Tim,
[tt]send()[/tt] takes a [tt]string[/tt] argument, so you’ll need to do something akin to:
c:send(string.char(0,0,0,0,0,6,1,4,0,0,0,8))
which will convert the binary into a string so you can pump it through [tt]send(…)[/tt]
You’ll see this in IORelay plugin when I need to send binary data:
http://code.mios.com/trac/mios_iorelay/browser/trunk/L_IORelay1.lua#L124
NOTE: You may not be able to print that string out, to [tt]luup.log()[/tt] etc, since it may not translate correctly to the underlying OS character set…[/quote]
That’s what I was looking for…thanks @Guessed and Futzle
I am not finding many examples of TCPIP conenctions so if any one out there has seen any send them my way!
If I can make this work it will open up 100’s of modules that can report to Vera…EG pressure, temperature, tanks levels, multiple digital inputs, relay outputs, frequency…on and on. The one thing I have noticed on this Forum is that there are lot’s of original thinkers…Coral Reef wave making to Green House automation. You name it…someone wants Vera to do it! Ha ;D
Regards
Tim Alls
Are you back on board the Vera ship?
Tim,
The other thing to note here is that, in most cases, you don’t need to do your own socket management. Of course, you can, but keeping the handles around may become problematic (since you don’t get a [tt][/tt] event in MiOS). Closing them on every request will give you a slight performance issue (typically minor, in LAN deployments)
If you’re only connecting to one socket target, like a TCP-Modbus bridging device, then you might be better off using the built-in Socket handling of MiOS itself.
A large number of Plugins do this, in one way or another.
In this model, you setup the criteria for the connection during startup processing, and then send IO using [tt]luup.io.write(…)[/tt], which does the write/flush on the socket…
All incoming IO is received in the [tt][/tt] block of the Plugin’s implementation, it comes in “chunks” of either CR-LF, STX-CTX, or RAW (char-by-char) to this action handler. In theory, MiOS takes care of keeping a TCP connection to the target TCPDevice (ip, port), and abstracts away a part of the IO - so you could be attached to a USB-Modbus adapter, with the same core codebase.
Since you’re probably dealing with RAW data (a guess), you can look at the following file for examples:
http://code.mios.com/trac/mios_onkyo-media-control/browser/trunk/I_OnkyoReceiver1.xml
This device can be attached either via TCP or via Serial, so you’ll also see that logic in startup… the rest of the code is the same for either mode.
Before you go too far on the Modbus stuff, it might pay to get the Temperature stuff working first (via HTTP/XML). You’re going to hit a number of programming/model constructs in that exercise that’ll help you with this one (a MiOS programming foundation, if you will)
[quote=“oTi@, post:9, topic:170475”]@TimAlls,
Are you back on board the Vera ship?[/quote]
Ha…hopefully not a sinking ship! I learned that the Vera is to be used in the home world and not the industrial world. I am working on some homeward projects…I built a new wood burning stove that has great fan powered heat exchangers…I want Vera to monitor the output temps and control the fans based on temperature readings. (I am using an industrial theremostat module listed in another thread)
@Guessed
Thanks for the feedback…The XML output was easy to read, I have that code working but didn’t finish the parsing yet. Before going into a Plugin I wanted to know if I could use the Modbus for communication which down the line would open up more options like writing to the modules as well as reading.
This programing is second nature to you…
It can be a bit overwhelming to me at times! I started with assembly language for the 6502 processor in 1975 and from there jumped straight to Labview…No C coding!
I am trying to relate everything I see to the equivalent code in Labview which might be a bad idea, it’s just what I understand.
In Labview I begin by opening a TCPIP connection, then keep the socket open for as long as I want, continue writing and reading to the module, and close the connection when exiting the program.
I have an advantage with Labview because I can write routines that test the connection between Vera and the PC…this shows me Byte by Byte what is going in and coming out.
I am not going to put too much time into it but I figured why not give it a shot!
Your code and others has been most helpful and I get a kick out of some of the comments you have floating around ;D
One quick question:
Where is the coding located in a plugin that defines what you see in the UI4?
Regards
Tim
I started with assembly language for the 6502 processor in 1975 and from there jumped straight to Labview......No C coding!That's ok, I stared with BASIC in 1979, then Z80 Assembler in '81. Lots of other languages in the middle, but didn't bother coding C until the 90's (and it was a short stint with TCP networking layers, the bulk of my professional-years code is in Java from it's inception)
One quick question: Where is the coding located in a plugin that defines what you see in the UI4?UI mappings, along with Event and Scene capability descriptions live in the .JSON file. It's an ugly hairball mess of a file that goes largely undocumented, and done "by example".
It has changed in subtle, yet significant, ways in UI5… enough to ensure that a UI4 plugin won’t work under UI5… visually at least… Weather, and a few others, have the JSON attribution required to support both UI4 and UI5 simultaneously, albeit at a loss of functionality.
Some time back, @futzle took a stab at documenting parts of it for UI4:
http://wiki.micasaverde.com/index.php/Luup_plugins:_Static_JSON_file
You might use that as a reference of sorts when looking at an existing JSON file. For things like Weather, only the “parent” needs one of these as all of the children are using standard UI building blocks (Temperature1, Humidity1, etc) that all have standard JSON files. This saves a bit of time…
I have been searching high and low for examples of how to use the tcpip socket library…I haven’t found a thing! I have been able to open the socket and send a data request but I cannot get the data back from the socket. I need to receive a fixed number of bytes from the socket and have them placed into a variable…anyone know the sequence?
@Guessed
Thanks for the information…I have a new text editor and I am stripping down a module to adapt…I am stuck on the modbus and continuing with the XML. This series of modules use XML to read and write so it will be it will be fully functional.
Some interesting things about this module:
Uses a One Wire Serial Bus for sensors…easy, flexible, and not much money
It can send Emails based on events …EG Temp 1 >85 degrees then…
It has three relay outputs that can be controlled using a basic script…EG
If temp1>85 and temp2 <95.1 then relay1=on
It is a pretty flexible Thermostat!
Regards
Tim Alls
If you just want to play with LuaSocket and TCP [Client] connections, you can do all that experimentation in a free-standing .lua file. These can be run outside of Vera, using Lua engine on a Mac/Windows/Linux etc, or simply from the Vera via SSH.
eg. “[tt]> lua testsocket.lua[/tt]”
This will let you rev your experiments quickly, without all the MiOS restart overheads. This is how I test basic Lua constructs (mostly string parsing stuff) whilst I’m working it out.
Note that in these cases, you wouldn’t ever “close” the socket, since you need to keep TCP Open in order to handle the response it’s going to send. The trick is there is no guarantee when (and if) that response will actually come… and in Vera, you can’t hang around forever, since it’ll fail on you, and restart the Lua engine, if something takes too long (> 30 seconds in UI4, > 60 seconds in UI5)
Either way, you’d need to paste a copy of what you’ve tried to do, Lua wise, so we can assist. I’ve not worked with that API, but from reading the doc I understand what parameters they’re looking for.
eg. [tt]data = c:receive(‘*a’) – if they close the socket when they’re done[/tt] OR;
eg. [tt]data = c:receive(50) – get 50 bytes back[/tt]
Timeouts etc don’t appear to be handled, so it could get really dodgy if it takes too long to return…
@Guessed,
As usual you have steered me well!
I installed the Lua Engine for Windows and ran a sucessful TCPIP socket connection with a test program written in Labview. This allowed me to watch the Lua code connect and receive the data that Labview was sending out. With this as starting place I should be able to switch to a modbus module on Monday and finish up…but first Honey Doo’s…oh well!
Thanks again…I will post my Modbus reading code as soon as I work the bugs out. Working on my desktop is sooooooo much easier…so nice to see error messages and allow variables to be printed out as you go!
Regards
Tim
One quick question…
In regards to time-outs, Labview allows for an open connection with no timeouts…can I do this with lua code?
What dangers would there be to leaving the connection open being that Vera can reboot and act crazy at times?!
Regards
Tim
A whole bag of problems.
Let’s say you open the socket in startup, and hold the handle in a per-device variable. In this case, you’ll be completely responsible for re-opening the connection when the TCP session dies (like a power cycle of the target device). If it dies when you’re not talking to it, you may not pickup any event-based IO that occurs until you next go to use [tt]send()[/tt] …
Additionally, and depending upon how future versions of Luup device initializations work, you could leak fileHandles (sockets) each time MiOS is restarted… You won’t have this problem now, as they’re basically nuking the entire process, but there’s been talk of a more incremental restart process, one where you wouldn’t have to “Save”, you’d simply incrementally “Edit”. Since we don’t know the semantics of Luup device restarts, it could be dodgy to depend upon the current process-base restart model.
If I were trying to do this, I’d use the standard set of , for IO blocks, along with code that initializes the connection[sup]*[/sup].
[sup]*[/sup] This isn’t foolproof either, as there are bugs where sometimes the core MiOS framework doesn’t know the TCP handle it has is no longer functional, and also doesn’t reconnect. The Brultech sees this, and I use a poll timer to “kick it in the A” periodically
@guessed
With polling times at one minute maximum maybe closing the connection each time is the safest way out.
This code reads an ADAM 6017 8 channel modbus module with an address of 192.168.1.203 :
local socket = require(“socket”)
host = “192.168.1.203”
c = assert(socket.connect(host, 502))
c:send(string.char(0,0,0,0,0,6,1,4,0,0,0,8))
data = c:receive(25)
luup.log (data)
c:close()
The data returned is eight 16 bit numbers…
00 00 00 00 00 13 01 04 10 80 02 80 08 80 05 80 08 80 02 80 05 80 02 7F FB
Anyone have a good way to break it apart and form the eight 16 bit words?
More to come
Regards
Tim Alls
Assuming this is coming back as bytes, then you can extract each byte from the string that comes back using:
Lua 5.1 Reference Manual
eg. [tt]data:byte(1)[/tt] gives you the first byte.
Then you’ll need to know if the data is big or little endian before forming the relevant Integers.
eg. [tt]stuff = data:byte(1) * 256 + data:byte(2)[/tt] OR;
eg. [tt]stuff = data:byte(1) + data:byte(2) * 256[/tt]
from the sound of your descriptions, the modBus stuff will only put down device data when you asked for it (req-response vs event-driven). If this is the case, then it’s likely you can safely close the socket between calls (with only minor perf loss, stuff that’s not worth worrying about)…
I’d still consider using the mechanisms of [tt][/tt] etc…
of course, that’s assuming the fn returns the data as a string. I actually have no idea what it returns, so you might want to run
[tt]luup.log(type(data))[/tt]
or
[tt]print(type(data))[/tt] in your free-standing version.
to see what type it really is…