Telnet LUA Script, to turn on/off device

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… :frowning:

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…

:sob:

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 :slight_smile:

I found the following online (https://elkin.de/logicmachine-telnet-user-script/ ) 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 ?