Hi @parkerc. Not sure if this may help? I wasted several hours recently trying to send commands to an iTach, and encountered the same problem that it worked OK sent as telnet from my PC but not as Lua code from Vera. I eventually found the problem to be that the device wanted the send string in double quotes rather than single quotes when sent from Vera. Try sending “S POWER 1\n”.
Hi @WarrenWills
Many thanks for that suggestion, unfortunately that doesn’t work either, plus some other variations e.g. ‘\r\n’ were suggested by @rigpapa too - but no luck there. Do you have some working code for your set up - that I could try ?
As I obtain an initial response when I connect, it’s clear I have the correct connection details, i can only think its the sequence or maybe a timing issue? I’ve tried to update the code so the command is sent twice at two different points, no luck there either.
Maybe It needs a luup.sleep or a luup_call.delay added, perhaps ?
local CommandtoSend = 'S POWER 1\r'
local CommandtoSend1 = 'S POWER 1\r'
print("Command is:", CommandtoSend)
function read(client, pattern, prefix)
local data, emsg, partial = c:receive(pattern, prefix)
if data then
return data
end
if partial and #partial > 0 then
return partial
end
return nil, emsg
end
local socket = require("socket")
host = "192.168.102.128" -- CYP
c = assert(socket.connect(host, 23))
c:setoption('tcp-nodelay', true)
c:settimeout(10)
local sres, serr = c:send(CommandtoSend)
print("Send:", sres, serr)
local data,emsg = read(c,2048,nil)
print("data=", data)
print("emsg=", emsg)
print("partial=", partial)
local sres, serr = c:send(CommandtoSend1)
print("Send:", sres, serr)
local data,emsg = read(c,2048,nil)
print("data=", data)
print("emsg=", emsg)
print("partial=", partial)
c:close()
Output from LuaTest is…
**Print output** Command is: S POWER 1 Send: 10 data= ==================================== Telnet command service command '?' for help command 'quit' for quit ==================================== emsg= partial= Send: 10 data= emsg= timeout partial=
There is a ‘timeout’ reported which make me wonder about the timing that things are sent to be read and write ?
This is the simple script that I use in a Vera scene to turn on my Optoma projector (wired Ethernet) and turn on a Panasonic Video Recorder (iTach using IR). I haven’t tried tweaking the luup sleep time - it works fine with (1050) so I left it at that.
local socket = require(“socket”)
host = “192.168.1.14”
port = 23
c = assert(socket.connect(host, port))
c:send(“~0100 1\r”)
luup.sleep(1050)
c:close()
local socket = require(“socket”)
host = “192.168.1.70”
port = 4998
c = assert(socket.connect(host, port))
c:send(‘sendir,1:3,1,37000,1,1,128,65,16,16,16,48,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,48,16,16,16,16,16,16,16,16,16,16,16,16,16,48,16,48,16,16,16,48,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,48,16,48,16,48,16,48,16,48,16,16,16,16,16,16,16,48,16,48,16,48,16,16,16,16,16,16,16,48,16,2742\r’)
luup.sleep(1050)
c:close()
Thanks @WarrenWillis
I gave it a go, as it made me wonder if the pause (luup.sleep) you had might play a part, but alas not - i still can’t get it to work via LUA code.
I’ve also had a go at some subtle variations of what I‘m sending too, but again still no luck…
local sres, serr = c:send("S POWER 1/r")
local sres, serr = c:send(string.char(0x0A).."S POWER 1"..string.char(0x0D))
local sres, serr = c:send(string.char(10).."S POWER 1"..string.char(13))
local sres, serr = c:send("S POWER 1"..string.char(0x0D))
I just can’t work out why i can control it by sending the same command ‘S POWER 1" via a telnet app, but not via lua code…
If you or anyone else reading this can think of anything else I could try, I’d appreciate it.
Ok, I stumbled across an interesting post/comment on Stack overflow, which suggests a sleep in-between commands. Of which there seems to be quite a few options
As I’m using lua sockets, it feels like this would be the best option.
local socket = require 'socket'
socket.sleep(0.2)
But now everything times out…
How can I best Include ‘sleep’ when I want to both send command and also read responses. Do things like and overall c:settimeout() becomes important? If so how best do you work out the timings between each action ? Trying to get the order/sequence correct.
Current code, which is running ok, but it’s still not turning the device on.
function read(client, pattern, prefix)
local data, emsg, partial = c:receive(pattern, prefix)
if data then
return data
end
if partial and #partial > 0 then
return partial
end
return nil, emsg
end
local socket = require("socket")
host = "192.168.102.128" -- CYP
c = assert(socket.connect(host, 23))
c:setoption('tcp-nodelay', true)
c:settimeout(10)
local data,emsg = read(c,2048,nil)
print("data=", data)
print("emsg=", emsg)
print("partial=", partial)
socket.sleep(0.2)
local sres, serr = c:send("S POWER 1/r")
print("Send:", sres, serr)
local data,emsg = read(c,2048,nil)
print("data=", data)
print("emsg=", emsg)
print("partial=", partial)
c:close()
LuaTest print output is still the same, it feels like I somehow need to keep the connection alive and then send the next command, but as you can see from the below, the second read times out, any ideas why ?
Print output
> data= ====================================
> Telnet command service
> command '?' for help
> command 'quit' for quit
> ====================================
>
> emsg=
> partial=
> Send: 11
> data=
> emsg= timeout
> partial=
This version works perfectly for me when run on the Vera using the lua
command on the command line (e.g. lua test.lua
if the code is saved in test.lua, but you can also run it directly by entering lua
with no filename and then pasting the code into the terminal window).
function read(client, pattern, prefix)
local data, emsg, partial = client:receive(pattern, prefix) -- fixed incorrect reference to "c"
if data then
return data
end
if partial and #partial > 0 then
return partial
end
return nil, emsg
end
socket = require("socket")
host = "192.168.0.100" -- CYP
c = socket.connect(host, 23)
print("Connected to",c:getpeername())
c:setoption('tcp-nodelay', true)
c:settimeout(5)
data,emsg = read(c,2048,nil)
print("data=", data)
print("emsg=", emsg)
-- print("partial=", partial) -- partial is not in scope here!
socket.sleep(0.2)
sres, serr = c:send("S POWER 1\r\n")
print("Send:", sres, serr)
data,emsg = read(c,2048,nil)
print("data=", data)
print("emsg=", emsg)
-- print("partial=", partial) -- partial is not in scope here!
c:close()
Scope seems to be the issue. It seems right to use local
in the outmost level of the program, but this has side-effects in Lua depending on how the code is run. For the way I was testing (lua
on command line) the local
declarations at the top level need to be removed. If you put this code in scene Lua, though, Vera wraps that in a function, so in that case, using local
is highly desirable. But that odd behavior of Lua isn’t the only scope issue, and you really need to learn how variable scope works and use it properly. You cannot write safe programs/plugins for Luup until you do.
Edit: here’s an example of the Lua oddity I’m referring to when on the command line. Counter-intuitive, isn’t it?
root@MiOS_XXXXXX:~# lua
Lua 5.1.5 Copyright (C) 1994-2012 Lua.org, PUC-Rio (double int32)
> local n = 5
> =n
nil
>
Many thanks @rigpapa
A few quick questions for you…
I’ve never used lua from the command line before; how and where do you save the files to on Vera, so they are accessible?
Does that same rule apply when I use LuaTest and the Vera UI under apps/develop apps/test luup code ?
When you SSH into Vera, most of the filesystem is available to you (except where it’s on read-only volumes). If you SSH in, the default home directory for the root user (which is /root
) is writable, so you can just put the file there.
“Test Luup Code” in the native UI wraps the code in a function (sort of, there are more details to that, but let’s just simplify it to that), so in this context, local
is recommended. I am not sure what “LuaTest” does (or is, I’ve never used it).
Awesome thanks @rigpapa
Well, based on what you shared- I’ve tried various ways now and sadly I still can’t seem to get it to do anything.
It’s clear it connects, as I get the initial response back, but for the life of me I just can’t understand why I can’t get a subsequent command to be recognised…
One other change in my version that may not be obvious… your version was sending S POWER 1/r
which uses the wrong /, you have to use backslash, as in S POWER 1\r
so make sure you captured that change as well.
Thanks @rigpapa, I sadly may have to admit defeat on this one.
I’ve been surfing around trying to find other working examples and have now also tried adding this to the code - But alas no luck…
client:setoption("keepalive", true)
client:setoption("reuseaddr", true)
Plus I found some code that adds a repeat, so I could repeatedly send the command. But alas no luck…
repeat
print("Sending message request...")
assert(client:send("S POWER 1" .. "\r"))
print("Message request sent! Waiting for message...")
data, errormsg = client:receive()
if data then
print("Message received!")
print(data)
else
print("Failed to receive message.")
break
end
until not client
LuaTest output.
Attempting connection to server '192.168.102.128' and port 23... Connected! Sending message request... Message request sent! Waiting for message... Message received! ==================================== Sending message request... Message request sent! Waiting for message... Message received! Telnet command service Sending message request... Message request sent! Waiting for message... Message received! command '?' for help Sending message request... Message request sent! Waiting for message... Message received! command 'quit' for quit Sending message request... Message request sent! Waiting for message... Message received! ==================================== Sending message request... Message request sent! Waiting for message... Failed to receive message.
Sadly I have to admit defeat on this one. If anyone comes across this thread and finds a way to communicate with an obviously stubborn device/telnet connection I’d love to hear it.
It’s clear a connection can be made, and the initial response is received, it’s just that no subsequent commands seem to be accepted.
I’m still surprised that there is not a generic (user customisable) app/plug-in for this sort of thing - one that creates a constant client connection to an IP connected device. These days theses types of connections often have the ability to capture status information as well as send commands.
Update
I found the following online (LogicMachine telnet user script | Home of ManagementBoy ) and modified it for my needs/target device and it works - BUT I have no idea why !!!
function telnet(host, port, command)
local socket = require("socket")
local tcp = assert(socket.tcp())
res, err = tcp:connect(host, port)
res, err = tcp:send(command)
while true do
local s, status, threebytes = tcp:receive(3)
if status == "closed" then break end
end
tcp:close()
end
telnet('192.168.102.128', 23, 'S SOURCE 1\r\n\r\nclose\r\n\r\n')
Problem is, once sent it locks up the target device and results in a luup reload on Vera - so it’s sadly not reusable quickly as I either have to wait for Vera to restart (I assume to release the telnet connection) or I have to power off/on the target device as it becomes unresponsive. (I have noticed looking back that the telnet connection to the target device is very fragile, it will lock up very easily.
Any ideas why the code above would work ?