Newbie Basic RS232 Plugin

I’m no where near an experienced programmer, but I’m taking bits and pieces from this form, using the wiki guide (http://wiki.micasaverde.com/index.php/Luup_Somfy_Walkthrough) to see what I can create.

The end result may not be pretty, but it’s my hope that the experienced who monitor this forum, will be able to help polish it up. :slight_smile:

First things first, I need to do more testing when I have the powered hub for the Pi - as that’s what’s going to be driving it.

My hope remains that it’ll hopefully be straight forward - all I want to do is send “023031323304” from Vera to my HDMI switch via a Raspberry Pi running Ser2net. - how difficult could that be :slight_smile: :slight_smile:

all I want to do is send "023031323304" from Vera to my HDMI switch via a Raspberry Pi running Ser2net. - how difficult could that be :) :)

If that is really all you want to do, Chris, send it from a scene and save yourself from the trials and tribulations of creating a plugin. :wink:

[quote=“RexBeckett, post:42, topic:169704”]

all I want to do is send “023031323304” from Vera to my HDMI switch via a Raspberry Pi running Ser2net. - how difficult could that be :slight_smile: :slight_smile:

If that is really all you want to do, Chris, send it from a scene and save yourself from the trials and tribulations of creating a plugin. ;)[/quote]

Where’s the fun/stress/dispair in all that :slight_smile:

I have potentially 13 codes to send - so if I can work it into a plugin that would cool. There does not seem to be a AV RS232 plugin any more for Vera so if it helps others I’m at least giving something back to this forum. 8)

But like you say @Rex - That’s always my fall back plan - I have the white flag on stand by.

well the thing is by sending it from a scene we would still need to have the proper code to be able to send it to the device… might as wel make a plugin then as you dont’t want to end up with 13 scenes, its a unlucky number lol
you can look at the samsung tv plugin i altered for having more buttons on the plugin control tab. it got like 40+ on it so that should be suffice.

Thanks @Da_JoJo. - I think I found yours here → http://forum.micasaverde.com/index.php/topic,7878.msg104980.html#msg104980

The .json file actually looks the most complicated to do, but taking what I’ve seen for the others files - this looks like it would create a button …

My interpretation is that the first part defines what it is, then how it is displayed and in what position and then finally what it does when pressed - which I think goes back to my I_HDMIMatrix1.xml file

{ "ControlType": "button", "Label": { "lang_tag": "InputA1", "text": "Input A1" }, "Display": { "Service": "urn:micasaverde-com:serviceId:InputSelection1", "Variable": "Input", "Value": "Input A1", "Top": 145, "Left": 10, "Width": 65, "Height": 20 }, "Command": { "Service": "urn:micasaverde-com:serviceId:InputSelection1", "Action": "InputA1", "Parameters": [] } },

yup thats the one :slight_smile:
json is indeed the most unfamiliar thing. from what i recall this button is created like u said and uses this serviceid to make the action… same as you would do a http request
something like this http:///port_3480/data_request?id=action&DeviceNum=112&serviceId=urn:upnp-org:serviceId:VSwitch1&action=SetTarget&newTargetValue=
so it needs an implementation file for these serviceid to tell what the serviceid must do when it is called.
im out of it for a while so you might want to look at a similar plugin for that.
edit:
ok so far i found this
implementation :

[code]

function thisfunction(variable,variable)
functionitself
return (datafunction)
end;

lug_startup


urn:micasaverde-com:serviceId:servicename
name for action

local command = “somecommand”
luup functioncall
luup.call_delay(“othercommand”)





d_device.json would be

    "imgIconBody": "",
    "imgIconDimmable": "",
    "imgIconTurnable": "",
    "imgIconMin": "",
    "imgIconMax": "",
    "state_icons": [],
    "halloIconsDir": "pics/hallo",
    "x": "3",
    "y": "4",
    "inScene": "1",
    "DisplayStatus": {},
    "doc_url": {
        "doc_language": 1,
        "doc_manual": 1,
        "doc_version": 1,
        "doc_platform": 0,
        "doc_page": "devices"
    },
    "Tabs": [
        {
            "Label": {
                "lang_tag": "tabname_control",
                "text": "Control"
            },
            "Position": "0",
            "TabType": "flash",
            "SceneGroup": [
                {
                    "id": "1",
                    "top": "0.25",
                    "left": "0",
                    "x": "3",
                    "y": "1"
                },
                {
                    "id": "2",
                    "top": "1",
                    "left": "0",
                    "x": "3",
                    "y": "3"
                }
            ],
            "ControlGroup": [
                {
                    "id": "1",
                    "type": "info", 
                    "scenegroup": "1"
                },
                {
                    "id": "2",
                    "scenegroup": "2",
                    "isSingle": "1"
                }
            ],
            "Control": [
                {
                    "ControlGroup": "2",
                    "ControlType": "button",
                    "top": "0",
                    "left": "0",
                    "Label": {
                        "lang_tag": "cmd_languagetag",
                        "text": "Play"
                    },
                    "Display": {
                        "Service": "urn:upnp-org:serviceId:servicename",
                        "Variable": "variable",
                        "Value": "value",
                        "Top": 30,
                        "Left": 30,
                        "Width": 50,
                        "Height": 20 
                    },
                    "Command": { 
                        "Service": "urn:micasaverde-com:serviceId:servicename", 
                        "Action": "doaction", 
                        "Parameters": [] 
                    } 
                },

[/code]
so
D_device tells what should be in the device popup screen and the device on vera UI … what function should be run when pressing button
I_implentation tells what functions and services are used
S_services tells what should be used as servicestates and in scene advanced… if variable is changed then update button for it on the UI
L_lua own made lua script to run stuff
confusing if u ask me…
check here http://forum.micasaverde.com/index.php/topic,13532.0.html for some more explanation on plugin creating

With a new hub installed I’m back to testing, however it seems the command successfully sent from the PC is not being accepted via the PI. However the good thing is it seems to show that there is a connection there.

LuaTest 1.5.2

Lua file: /nas/matrixtest.lua

Results
No errors
Runtime: 141.4 ms
Code returned: nil

Print output
Send: 10
Receive: 0

**Invalid Input. Refer to Install Guide or FAQ (www.octavainc.com)for serial control protocol.

Code
1 local socket = require(“socket”)
2 host = “192.168.1.77”
3 c = assert(socket.connect(host, 4001))
4 local sres, serr = c:send(“0230303603”)
5 print(“Send:”, sres, serr)
6 local data, rerr = c:receive(100)
7 luup.log (data)
8 print (“Receive:”, data, rerr)
9 c:close()
10
11

Is there anything I can try / add to the code to help or to troubleshoot?

The document linked states that the commands must be sent as hex. You are sending a string of decimal digits. Change this to:

 local sres, serr = c:send(string.char(0x02,0x30,0x30,0x36,0x03))

You are the man !! - It works

LuaTest 1.5.2

Lua file: /nas/matrixtest.lua

Results
No errors
Runtime: 340.9 ms
Code returned: nil

Print output
Send: 5
Receive: 212E

Status code:11211111111

**Refer to Install Guide or FAQ (www.octavainc.com) for serial c

Code
1 local socket = require(“socket”)
2 host = “192.168.1.77”
3 c = assert(socket.connect(host, 4001))
4 – local sres, serr = c:send(“0231323103”)
5 local sres, serr = c:send(string.char(0x02,0x32,0x31,0x32,0x03))
6 print(“Send:”, sres, serr)
7 local data, rerr = c:receive(100)
8 luup.log (data)
9 print (“Receive:”, data, rerr)
10 c:close()
11
12

You are the man !! - It works

I’m glad to hear it. I recommend you set a timeout for your socket, though. Otherwise, if your Pi is off the air, the receive call will block and cause a Vera restart. Place this as line 4:

c:settimeout(5)

Thanks again @Rex - Yes, I think I have had that timeout issue before when I’ve locked up Vera…

local socket = require("socket") host = "192.168.1.77" c = assert(socket.connect(host, 4001)) c:settimeout(5) local sres, serr = c:send(string.char(0x02,0x32,0x31,0x32,0x03)) print("Send:", sres, serr) local data, rerr = c:receive(100) luup.log (data) print ("Receive:", data, rerr) c:close()]

Hi.

As I have 13 possible actions, rather than a mapping table which I was taking from the Pioneer Receiever plugin can I just put the required code against each Action on the I_HDMiMatrix1.xml ? I’ve replaced the Print entries used with Lua Test with luup.log

<action> <serviceId>urn:micasaverde-com:serviceId:InputSelection1</serviceId> <name>InputA1</name> <run> local socket = require("socket") host = "192.168.1.77" c = assert(socket.connect(host, 4001)) c:settimeout(5) local sres, serr = c:send(string.char(0x02,0x32,0x31,0x31,0x03)) luup.log ("Send:", sres, serr) local data, rerr = c:receive(100) luup.log ("Receive:", data, rerr) c:close() </run> </action>

However - as the start up function I’m tweaking from the Pioneer plugin is this…

[code]function doStartup(lul_device)
local PORT = 4001
ipAddress = luup.devices[lul_device].ip

        if (ipAddress ~= "") then
            luup.log("Running Network Attached HDMI Matrix via a RaspBerry Pi on " .. ipAddress)
            luup.io.open(lul_device, ipAddress, PORT)
        else
            luup.log("Running Serial Attached I_HDMIMatrix1.xml - THIS IS UNTESTED")
        end
    end[/code]

Could I potentially use the following instead as the IP address and host are (I think) already defined ?

<action> <serviceId>urn:micasaverde-com:serviceId:InputSelection1</serviceId> <name>InputA1</name> <run> local socket = require("socket") c = assert(socket.connect(ipAddress, PORT)) c:settimeout(5) local sres, serr = c:send(string.char(0x02,0x32,0x31,0x31,0x03)) luup.log ("Send:", sres, serr) local data, rerr = c:receive(100) luup.log ("Receive:", data, rerr) c:close() </run> </action>

Your idea is right, but you’ll need to modify the code a bit more than that because the doStartup function makes PORT [tt]local[/tt]. Local variables disappear again as soon as their enclosing code (the doStartup function in this case) exits.

To make the variable global, simply remove the word [tt]local[/tt]:

function doStartup(lul_device) PORT = 4001 ipAddress = luup.devices[lul_device].ip -- ...
This variables-are-global-unless-declared-local policy is common in scripting languages.

In production code you’d probably want some more error checking on ipAddress, but since you are your own customer for this plugin you just know that you have to have the “IP” field filled in for this device.

Perhaps the next thing for you to try is to see if you can take the socket.connect() calls out of each individual action, and do a single connect in doStartup(), with c now a global variable. This would only make sense if you intend for the connection between Vera and your HDMI matrix to be persistent. That would be a prerequisite for having Vera detect when the matrix has been altered by some other party (such as its infrared remote).

Thanks @futzle

Ok, so to make more ‘global’ and to allow Vera to capture any ad-hoc changes that might be made’ it sounds like I could do the following to the doStart function.

Is it ok to also move the received elements there as well, leaving the just the send code as part of the action.

[code]function doStartup(lul_device)
PORT = 4001
ipAddress = luup.devices[lul_device].ip
socket = require(“socket”)
c = assert(socket.connect(ipAddress, PORT))
data, rerr = c:receive(100)
luup.log (“Receive:”, data, rerr)

        if (ipAddress ~= "") then
            luup.log("Running Network Attached HDMI Matrix via a RaspBerry Pi on " .. ipAddress)
            luup.io.open(lul_device, ipAddress, PORT)
        else
            luup.log("Running Serial Attached I_HDMIMatrix1.xml - THIS IS UNTESTED")
        end
    end[/code]

Allowing the action to be just… ?

<action> <serviceId>urn:micasaverde-com:serviceId:InputSelection1</serviceId> <name>InputA1</name> <run> c:settimeout(5) local sres, serr = c:send(string.char(0x02,0x32,0x31,0x31,0x03)) luup.log ("Send:", sres, serr) c:close() </run> </action>

Do I want it to close c: at the end ?

No, the “receive” code will have to be moved into the section of your implementation file, We’ll talk about that later.

Do I want it to close c: at the end ?

Definitely not. That would prevent the next action from accessing the socket at all. In fact, you should leave the socket open and never call close().

Now for the next batch of changes. One is that manipulating the socket yourself is counterproductive in Luup plugins where you want a persistent connection: it doesn’t let the plugin react to any received data because the code to receive data is inside the plugin and you need it outside. To fix that, switch to using luup.io.* calls, which the LuaUPnP will monitor on your behalf. Two is to handle incoming data asynchronously by moving it to the section. This code will be called every time a byte comes in on the serial connection. For the moment I’m just logging it but later on we’ll use that to change the device’s state variables.

<implementation>
  <settings>
    <protocol>raw</protocol>  <!-- maybe? -->
  </settings>
  <functions>
function doStartup(lul_device)
  PORT = 4001
  ipAddress = luup.devices[lul_device].ip
  luup.io.open(lul_device, ipAddress, PORT))  -- This replaces socket.connect()
  -- luup.log and other stuff from your original startup code
end
  </functions>
  <incoming>
    <lua>luup.log("Received byte " .. string.byte(lul_data))</lua>
  </incoming>
  <actionList>
    <action>
      <serviceId>urn:micasaverde-com:serviceId:InputSelection1</serviceId>
      <name>InputA1</name>
      <run>
        luup.io.send(string.char(0x02,0x32,0x31,0x31,0x03))  -- This replaces c:send().
        -- luup.log() and other stuff.
      </run>
    </action>
  </actionList>
  <!-- more actions -->
</implementation>

Keep a copy of your working plugin from a few days ago. This experiment may conflict with the AV Matrix in ways that we can’t predict so we may have to go back to it.

Hi @fuztle

Thanks, quick question…

To switch to luup.io.* with confidence, shouldn’t the following code work?

luup.io.write(string.char(0x02,0x32,0x31,0x31,0x03),"192.168.1.77", 4001)

So far it doesn’t and I can’t make it change the input on the matrix ? Is there something wrong with code used above?

There is no three-argument version of luup.io.write(), so, no, I don’t expect that code to work. The second “device” parameter is either a number (lul_device in your code), or a string the same as a device’s local_udn (see the Advanced tab), or it can be entirely absent, in which case it uses the “current” device. I always do the latter in my plugins.

[quote=“parkerc, post:51, topic:169704”]Thanks again @Rex - Yes, I think I have had that timeout issue before when I’ve locked up Vera…

local socket = require("socket") host = "192.168.1.77" c = assert(socket.connect(host, 4001)) c:settimeout(5) local sres, serr = c:send(string.char(0x02,0x32,0x31,0x32,0x03)) print("Send:", sres, serr) local data, rerr = c:receive(100) luup.log (data) print ("Receive:", data, rerr) c:close()][/quote]

Parkerc, has this worked for you?

I tried this without succes

"local socket = require(“socket”)
client = assert(socket.connect(“192.168.1.70”, 4999))
if (client == “nil” or client == nil) then
luup.log(“La connexion a echouee”)
else
luup.log(“Connexion OK”)
end
c:settimeout(5)
local sres, serr = c:send(string.char(x02,x04,xa0,x42,x00,x22,xf8,x03))
print(“Send:”, sres, serr)
local data, rerr = c:receive(100)
luup.log (data)
print (“Receive:”, data, rerr)
c:close()
"

Can anyone point me what is wrong?
I’m trying to control a Sony receiver by RS232
this code works with hercules: “\x02\x04\xa0\x42\x00\x22\xf8\x03”

Can anyone point me what is wrong?

You have changed the name of the socket object but not changed all the references to it. Try:

local socket = require("socket") client = assert(socket.connect("192.168.1.70", 4999)) if (client == "nil" or client == nil) then luup.log("La connexion a echouee") else luup.log("Connexion OK") end client:settimeout(5) local sres, serr = client:send(string.char(x02,x04,xa0,x42,x00,x22,xf8,x03)) print("Send:", sres, serr) local data, rerr = client:receive(100) luup.log (data) print ("Receive:", data, rerr) client:close()

Thx for your quick reply!
Stupid mistake, but that did not solve the problem!