Author Topic: Act on response from usb to serial device command.  (Read 502 times)

Offline parkerc

  • Sr. Hero Member
  • ******
  • Posts: 2330
  • Karma: +32/-44
  • Life Moves Pretty Fast....
    • Node Central
Act on response from usb to serial device command.
« on: September 07, 2017, 05:42:40 pm »
Hi

I'm looking for some help with the following code.

It seems to run successfully (the matrix's Input changes and a response is captured) but it doesn't seem to progress (and print out) the required analysis  results/response based on what the the HDMI matrix sent back.

Code: [Select]
function HDMIA1()
local socket = require("socket")
host = "192.168.1.204"
c = assert(socket.connect(host, 4002))
c:settimeout(5)
local sres, serr = c:send(string.char(0x02,0x32,0x31,0x31,0x03))
print("Send:", sres, serr)
local data, rerr = c:receive(175)
luup.log (data)
print ("Receive:", data, rerr)
c:close()

-- if successful the hdmi switch will return a message which includes the words "Status code:100031111110001" - so I've tried to use a lua expression to extract that if it's there.

local result = data:match "%a+%s%a+:%d+"
print ("" ..result)

if (result == "Status code:100031111110001")
         then
         luup.log("it worked")
         print("it worked")
if (result ~=  "Status code:100031111110001")
         then
         luup.log("it failed")
         print("it failed")
else print("neither were seen it has just failed")
end
end
end

HDMIA1()
« Last Edit: September 07, 2017, 08:33:05 pm by parkerc »

Online akbooer

  • Master Member
  • *******
  • Posts: 5131
  • Karma: +221/-67
  • "Less is more"
Re: Act on response from usb to serial device command.
« Reply #1 on: September 07, 2017, 06:17:03 pm »
You're expecting exactly 175 bytes to be returned?  Unwise.

Also, the timeout() call has a problem in some implementations.
3x Vera Lite-UI5/Edge-UI7, 25x Fibaro, 23x TKB, 9x MiniMote, 2x NorthQ Power, 2x Netatmo, 1x Foscam FI9831P.
Razberry, MySensors Arduino, HomeWave, AltUI, DataYours, openLuup, ZWay, ZeroBrane Studio.

Offline parkerc

  • Sr. Hero Member
  • ******
  • Posts: 2330
  • Karma: +32/-44
  • Life Moves Pretty Fast....
    • Node Central
Re: Act on response from usb to serial device command.
« Reply #2 on: September 07, 2017, 06:44:43 pm »
Hi @akbooer

I had gradually increased the byte size so I could see more of what's returned - so I can easily trim that a bit, but as the connection uses Ser2net it seems I will still need quite a bit to ensure I capture the required status code.

This is what Luatest returns.

Quote
LuaTest

LuaTest 1.5.2

Lua file: /nas/luatest/octavia.lua

Results
No errors
Runtime: 866.0 ms
Code returned: nil

Print output
Send:     5     
Receive:     ????????
ser2net port 4002 device /dev/ttyUSB0 [9600 N81] (Debian GNU/Linux)

S211E

Status code:100011111110001

**Refer to Install Guide or FAQ (www.octavainc.com)f     


Status code:100011111110001     

 

Does the use of a  timeout impact the running of all the code? I assumed the timeout who just related to the socket (USB/serial) connection ?
« Last Edit: September 07, 2017, 07:01:31 pm by parkerc »

Offline jswim788

  • Sr. Member
  • ****
  • Posts: 483
  • Karma: +23/-2
Re: Act on response from usb to serial device command.
« Reply #3 on: September 07, 2017, 08:15:13 pm »
Your if/else check doesn't look like it is what you want.  If I add some indentation (no code change), you can see it won't get to the inner statements unless the first if statement is true:
Code: [Select]
if (result == "Status code:100031111110001") then
  luup.log("it worked")
  print("it worked")
  if (result ~=  "Status code:100031111110001") then
    luup.log("it failed")
    print("it failed")
  else
    print("neither were seen it has just failed")
  end
end
You probably want something like this:
Code: [Select]
if (result == "Status code:100031111110001") then
  luup.log("it worked")
  print("it worked")
else
  luup.log("it failed")
  print("it failed")
end
But that's only relevant if you can get to that point; I'm not an expert on the receive data portion of your code.

Offline parkerc

  • Sr. Hero Member
  • ******
  • Posts: 2330
  • Karma: +32/-44
  • Life Moves Pretty Fast....
    • Node Central
Re: Act on response from usb to serial device command.
« Reply #4 on: September 07, 2017, 08:31:45 pm »
Hi @Jswim788

Thanks for that,

As the message being returned acts as either confirmation of a success transaction or a failure of one - I felt i needed to be more specific in my checking.

Unless I'm mistaken, wouldn't having just the one 'if' mean that the "else" will by default work as a catch all else - and not only be returned with a mismatch but also if there is any failure in the code itself etc?

I did not realise that things on,y progress if the first 'if' is met, therefore is this a situation where using  'elseif' is a better route ?
« Last Edit: September 07, 2017, 08:34:03 pm by parkerc »

Offline jswim788

  • Sr. Member
  • ****
  • Posts: 483
  • Karma: +23/-2
Re: Act on response from usb to serial device command.
« Reply #5 on: September 07, 2017, 11:13:07 pm »
I did not realise that things on,y progress if the first 'if' is met, therefore is this a situation where using  'elseif' is a better route ?
Yes, elseif is what you want.  The "then" to the "end" are all qualified by that first "if".  So definitely you want an "elseif".

The 2 checks you have looked identical to me.  So it looked like this:

  if result = "something" then
    do stuff
  end
  if result ~= "something" then
    do other stuff
  end

which can be replaced with a simple "else".  But maybe you intended for the 2 string checks to be unique?  (Or maybe they are and I got lost in the string!)

Offline parkerc

  • Sr. Hero Member
  • ******
  • Posts: 2330
  • Karma: +32/-44
  • Life Moves Pretty Fast....
    • Node Central
Re: Act on response from usb to serial device command.
« Reply #6 on: September 08, 2017, 03:06:13 am »
Ok, so as I would like to be more specific in my checking of the response/result is this what you are suggesting -  to do it in sort of blocks ?

Code: [Select]
if result ==  "Status code:100031111110001"
        print ("Expected status code received - so success")
elseif result ~=  "Status code:100031111110001"
        print ("Unexpected status code received - so failure ")
else
        print ("Something else happened, it likely failed  ")
end

HOLD ON - I've just realised I'm not making myself clear, the reason for the second "~=" check is to identify if another status code (which I do not know) is returned/received - but I can see now that the code I've done is no where near as intelligent as it needs to be to work that out:

How would I do a wild card type check of the numbers returned after the "Status Code:" text to report they are different - The status code I've specifically listed  looks to the one provided when the command was received successful, but I want the code to be open to receiving others, even if I have not been able to see any yet (BTW - there is no manual for these codes)  ?

 
« Last Edit: September 08, 2017, 03:17:00 am by parkerc »

Online akbooer

  • Master Member
  • *******
  • Posts: 5131
  • Karma: +221/-67
  • "Less is more"
Re: Act on response from usb to serial device command.
« Reply #7 on: September 08, 2017, 06:20:42 am »
I had gradually increased the byte size so I could see more of what's returned

Why don't you simply read all of the response?  Then you're sure to capture what you need...

Code: [Select]
local data, rerr = c:receive "*a"

How would I do a wild card type check of the numbers returned after the "Status Code:" text to report they are different

In fact, in Lua, multiple if-then-elseif statements are rarely appropriate.  Lua has associative arrays, and that means that anything can be an array subscript.

I'd suggest that you just strip out the relevant status code return from the response string and use it as an array subscript.  Lua does all the checking for you in optimised code...

Code: [Select]
local result = data: match "Status code:(%d+)" or "error"

message = {
  ["error"] = "Something else happened, it likely failed",
  ["100031111110001"] = "Expected status code received - so success",
  -- extend this with new codes when needed
}

print (message[result] or "Unexpected status code received - so failure")

It's neat, easy to extend, and much more readable.

If you actually need to do different things, rather than just print a response, you put functions into the 'message' array, rather than messages, and call them...

Code: [Select]
local result = data: match "Status code:(%d+)" or "error"

local function success_action (...)
  -- whatever
end

local function unknown_action (...)
  -- whatever else
end

local function error_action (...)
  -- something to do when things go wrong
end

action = {
  ["error"] = error_action,
  ["100031111110001"] = success_action,
  -- extend this with new codes when needed
}

(action[result] or unknown_action) (any_parameters_you_like)


Now you're starting to use some of the real power of the Lua language.
3x Vera Lite-UI5/Edge-UI7, 25x Fibaro, 23x TKB, 9x MiniMote, 2x NorthQ Power, 2x Netatmo, 1x Foscam FI9831P.
Razberry, MySensors Arduino, HomeWave, AltUI, DataYours, openLuup, ZWay, ZeroBrane Studio.

Offline parkerc

  • Sr. Hero Member
  • ******
  • Posts: 2330
  • Karma: +32/-44
  • Life Moves Pretty Fast....
    • Node Central
Re: Act on response from usb to serial device command.
« Reply #8 on: September 08, 2017, 06:38:09 am »
Thanks @akbooer

My head hurts :)   -  I love this stuff , but really struggle to grasp all the nuances :)

Ok, it seems I'm going to need to create a function for all the key steps  - which I guess will be as follows
  • Send hex command to matrix and capture response
  • Intepret response from matrix and call appropriate function either success or failure
  • The command was successful function
  • The command failed function
As the only difference in the command code is the hex value used, it would make sense to just send the function request with the required hex value provided via an argument. Assuming I have got the terminology right :)

1) The Matrix Hex Command function

This route currently fails as I think the commas needed in the argument part breaks it ? Is there a way around this so the various hex value can be provided in a way that they are passed into the function correctly  ?

Code: [Select]
function matrix_hex_command(hexcode)
local socket = require("socket")
host = "192.168.1.204"
c = assert(socket.connect(host, 4002))
c:settimeout(5)
local sres, serr = c:send(string.char(hexcode))
local data, rerr = c:receive "*a"

local result = data: match"Status code:(%d+)"
c:close()

matrix_hex_response()
end

This is how I'm thinking I can then send the matrix hex command...

Code: [Select]
matrix_hex_command(0x02,0x32,0x31,0x31,0x03)
2) The Matrix Hex Interpretation Function

I've assumed this should be called as the final part of the matrix hex command function. However I'm not sure how the

Code: [Select]
local function matrix_hex_interpretation()

-- ok so this is an array and I can call functions from this based on the result ?

action = {  ["100031111110001"] = command_successful(), 
                 ["100031111110001"] = command_failed(), 
                 -- extend this with new codes when needed}
end

Question : how does the interpretation function see the response from the matrix to do it's action.

3) Command was Successful Function

Action - this is to be worked on I would like to look at using luup.task to show the results in the Vera information window

Code: [Select]
Local function command_successful ()
. . .
end


4) Command sent failed Function
To be worked on - same reason as above.


Code: [Select]
Local function command_failed ()
. . .
end



Please let me know your thoughts ?
« Last Edit: September 08, 2017, 06:46:38 am by parkerc »

Online akbooer

  • Master Member
  • *******
  • Posts: 5131
  • Karma: +221/-67
  • "Less is more"
Re: Act on response from usb to serial device command.
« Reply #9 on: September 08, 2017, 07:14:08 am »
Ah, you caught my response before I edited it.  If you re-read it, you may find it a bit clearer.  My mistake was to think that you already had two different return codes to deal with but, looking at the array, I see they were the same code.  I refactored slightly, but the intention and approach is the same. 

Quote
Ok, it seems I'm going to need to create a function for all the key steps

That's really good practice, anyway.

Quote
The Matrix Hex Command function

Depending on the device you're communication with, you may not need to create a new TCP connection for every command?  I don't know, you'd need to refer to the documentation.  Either way, I'd not have the require statement in the, since it only needs to be done once.

string.char() takes multiple arguments, doesn't matter how many or what they're called, so I'd write this as what's called a variadic function:

Code: [Select]
function matrix_hex_command(...)
-- your previous code here
local sres, serr = c:send(string.char(...))
-- etc.
end

Quote
Question : how does the interpretation function see the response from the matrix to do it's action.

Just pass it the value in you call invocation:

Code: [Select]
(action[result] or unknown_action) (result)

I hope it makes it clearer.  If not, ask again.
3x Vera Lite-UI5/Edge-UI7, 25x Fibaro, 23x TKB, 9x MiniMote, 2x NorthQ Power, 2x Netatmo, 1x Foscam FI9831P.
Razberry, MySensors Arduino, HomeWave, AltUI, DataYours, openLuup, ZWay, ZeroBrane Studio.

Offline parkerc

  • Sr. Hero Member
  • ******
  • Posts: 2330
  • Karma: +32/-44
  • Life Moves Pretty Fast....
    • Node Central
Re: Act on response from usb to serial device command.
« Reply #10 on: September 08, 2017, 09:08:11 am »
Hi @akbooer

OK - this is great stuff, not sure I follow everything, but with yours and others help - I'm going to try and work through this step by step.  :-) So lets start with the initial Send Matrix Hex Command function

Objective - Is to send a HEX command to a HDMI Matrix Switch and capture the response that comes back, for another function to analyse/invoke actions.

The use of a 'variadic function' looks to have solved the matrix_hex_command function - thanks so much for that ! That allows me to use just the following code now to make changes.

Code: [Select]
matrix_hex_command(0x02,0x32,0x31,0x32,0x03)
Regarding "local data, rerr = c:receive "*a" that does not return anything and always times out, even if i extend to c:settimeout () to 10 seconds.
Only specifying a  number of bytes e.g "local data, rerr = c:receive(205)" seems to return information  ** Howrver 208 bytes seems to be the max, any more and it times out too **

My mistake was to think that you already had two different return codes to deal with but, looking at the array, I see they were the same code.  I refactored slightly, but the intention and approach is the same. 

Sorry that's my mistake  - after further testing there are other "Status Codes" values that come back if the request sent was successful, and there could be more, hence the array idea to capture and log them seems a great idea idea.

Output A - Input 1 = Status code:100011111110101
Output A - Input 2 = Status code:100021111110101
Output A - Input 3 = Status code:100031111110101
Output A - Input 4 = Status code:100041111110101

Output B - Input 1 = Status code:100021211110101
Output B - Input 2 = Status code:100022211110101
Output B - Input 3 = Status code:100023211110101
Output B - Input 3 = Status code:100024211110101

Output C & D to do..

Power On = Status code:100024231110101
Power Off = Status code:100024231110000

Code

Code: [Select]
function send_matrix_hex_command(...)
local socket = require("socket")
host = "192.168.1.204"
c = assert(socket.connect(host, 4002))
c:settimeout(5)
local sres, serr = c:send(string.char(...))
-- local data, rerr = c:receive "*a"
local data, rerr = c:receive(205)
print ("Receive:", data, rerr)
c:close()


luup.call_delay("matrix_reply_interpretation", 1)
end

Then the required HEX commands/calls can be done using this format..
Code: [Select]

send_matrix_hex_command(0x02,0x32,0x31,0x31,0x03)


Does that look good ?
« Last Edit: September 08, 2017, 09:36:29 am by parkerc »

Offline parkerc

  • Sr. Hero Member
  • ******
  • Posts: 2330
  • Karma: +32/-44
  • Life Moves Pretty Fast....
    • Node Central
Re: Act on response from usb to serial device command.
« Reply #11 on: September 08, 2017, 09:33:45 am »
For reference here are all the HEX Code commands i can send.

Code: [Select]
-- Output A
-- send_matrix_hex_command(0x02,0x32,0x31,0x31,0x03)
-- send_matrix_hex_command(0x02,0x32,0x31,0x32,0x03)
-- send_matrix_hex_command(0x02,0x32,0x31,0x33,0x03)
-- send_matrix_hex_command(0x02,0x32,0x31,0x34,0x03)

-- Output B
-- send_matrix_hex_command(0x02,0x32,0x32,0x31,0x03)
-- send_matrix_hex_command(0x02,0x32,0x32,0x32,0x03)
-- send_matrix_hex_command(0x02,0x32,0x32,0x33,0x03)
-- send_matrix_hex_command(0x02,0x32,0x32,0x34,0x03)

-- Output C
-- send_matrix_hex_command(0x02,0x32,0x33,0x31,0x03)
-- send_matrix_hex_command(0x02,0x32,0x33,0x32,0x03)
-- send_matrix_hex_command(0x02,0x32,0x33,0x33,0x03)
-- send_matrix_hex_command(0x02,0x32,0x33,0x34,0x03)

-- Output D
-- send_matrix_hex_command(0x02,0x32,0x34,0x31,0x03)
-- send_matrix_hex_command(0x02,0x32,0x34,0x32,0x03)
-- send_matrix_hex_command(0x02,0x32,0x34,0x33,0x03)
-- send_matrix_hex_command(0x02,0x32,0x34,0x34,0x03)

-- Port Status
-- send_matrix_hex_command(0x02,0x30,0x30,0x31,0x03)

-- LED On
-- send_matrix_hex_command(0x02,0x30,0x30,0x33,0x03)

-- LED Off
-- send_matrix_hex_command(0x02,0x30,0x30,0x34,0x03)

-- Power On
-- send_matrix_hex_command(0x02,0x30,0x30,0x35,0x03)

-- Power Off
-- send_matrix_hex_command(0x02,0x30,0x30,0x36,0x03)

Online akbooer

  • Master Member
  • *******
  • Posts: 5131
  • Karma: +221/-67
  • "Less is more"
Re: Act on response from usb to serial device command.
« Reply #12 on: September 08, 2017, 09:42:59 am »
Once again, I'd recommend that you move the require statement to outside the function.

The assert statement will raise an error if the connection fails, this is probably not what you want.

I don't get what the call_delay is all about.
3x Vera Lite-UI5/Edge-UI7, 25x Fibaro, 23x TKB, 9x MiniMote, 2x NorthQ Power, 2x Netatmo, 1x Foscam FI9831P.
Razberry, MySensors Arduino, HomeWave, AltUI, DataYours, openLuup, ZWay, ZeroBrane Studio.

Offline parkerc

  • Sr. Hero Member
  • ******
  • Posts: 2330
  • Karma: +32/-44
  • Life Moves Pretty Fast....
    • Node Central
Re: Act on response from usb to serial device command.
« Reply #13 on: September 08, 2017, 09:51:00 am »
Once again, I'd recommend that you move the require statement to outside the function.

The assert statement will raise an error if the connection fails, this is probably not what you want.

I don't get what the call_delay is all about.

By  "move the require statement out" you mean I should call it before the function, and is the same true for the assert statement too (whatever that is ?) ?

Code: [Select]
local socket = require("socket")
c = assert(socket.connect(host, 4002))

function send_matrix_hex_command(...)
   host = "192.168.1.204"
   c:settimeout(5)
   local sres, serr = c:send(string.char(...))
   local data, rerr = c:receive(205)
   print ("Receive:", data, rerr)
   c:close()

luup.call_delay("matrix_reply_interpretation", 1)

end

I don't get what the call_delay is all about.

I'm assuming i need to wait at least a second for the response to be ready for the matrix_reply_interpretation function to then be called to do it's thing and analyse the results ?  Is that not the case ?

Online akbooer

  • Master Member
  • *******
  • Posts: 5131
  • Karma: +221/-67
  • "Less is more"
Re: Act on response from usb to serial device command.
« Reply #14 on: September 08, 2017, 10:04:55 am »
This is what I was asking previously.  If you want to make a new connection each time, you need the connect within the function.  I wouldn't use assert.  As it is you've got the variable 'host' undefined at the point it's used.

I'm not sure that this very iterative approach is quite the way forward.
3x Vera Lite-UI5/Edge-UI7, 25x Fibaro, 23x TKB, 9x MiniMote, 2x NorthQ Power, 2x Netatmo, 1x Foscam FI9831P.
Razberry, MySensors Arduino, HomeWave, AltUI, DataYours, openLuup, ZWay, ZeroBrane Studio.