how-to: mirroring select openLuup devices/variables on real Vera

You’re not the first to ask…

http://forum.micasaverde.com/index.php/topic,34467.msg254674.html#msg254674

…and for exactly the same reasons.

You also point out some of the problems to do with race conditions, and you’re quite correct about dummy devices not consuming much in the way of resources.

This would have to be “thoroughly thought through.”

Any further ideas on requirements?

Oops… I missed that other post. Indeed similar situation.

I’ll think through it further and might send you some ideas/contributions in the next few days, but fundamentally the benefits should be:

[ul][li] allowing logic on the Vera to use openLuup device states/variables for inputs.[/li]
[li] allowing the use of the MiOS relays for remote access (basically the Vera and the openLuup systems can be see as one single system - with the Vera as the host - for applications like Homewave). Therefore all the existing ecosystem of remote apps can be extended to openLuup without any modification or tweak (rather then relying on a VPN or Weaved.[/li][/ul]

So a fundamental need would be that changes, specifically device variable changes, to a particular device on openLuup would be mirrored on the Vera, but you would not expect any Vera-based device or code to write to its variables, only read from them.

It would not make sense to have any actions implemented for such a device, since there is no Vera-based implementation code. This is entirely complementary to bridged devices on openLuup, which respond to action requests (by passing them to Vera) but have essentially read-only variables (in fact, any variables changes are simply NOT passed backwards by the bridge to Vera and get overwritten by the latest state from Vera.)

I would concur with that approach for “dummy” Vera devices just to mirror their original counterpart on openLuup and have actions passed to openLuup as you describe. As far as I can see this should allow achieving the two objectives I set forth.

I know Akbooer is working on an upgrade to the VeraBridge plugin that could include a similar feature (and most probably much more sophisticated than mine…), but I felt it could be useful in the meantime to share what I implemented on my openLuup and companion Vera…

The rationale for this is two fold:
1 - enable the piece of my logic on the real Vera that I could not yet migrate to openLuup to obtain data from the other pieces that I have moved to openLuup
2 - enable “out of the box” read of some variables that reside on the openLuup system from the remote apps I use to connect to the Vera (e.g. HomeWave) through the MiOS relays. Since my Vera system is in a vacation home, easy remote access is paramount (a VPN needs to be started/disconnected in addition to launching the app or the browser… Same for weaved.com that needs a user/password input in a browser)

Here is the “how-to”… it is long and a bit complex so it is not for the faint hearted !

Important: the below instructions are used at your own risk and assume you know what you are doing… Some of these changes may render either your Vera or your openLuup system unusable.

A) on the real Vera:

1) create the dummy device(s) that will be the mirror(s) and host the mirrored variables

the easiest method is to use the “create device” option in the AltUI “Devices” menu: you wil be presented 3 input boxes. Only the first two should be filled (we are creating dummy devices, so we do not want/need to register an I_xxx.xml implementation file). For instance:

Device Name: Temperature Mirror
D_xxx.xml filename: D_TemperatureSensor1.xml

and click the “Save Changes” button. After AltUI creates the device(s) (you might need to refresh your brower), please make note of the device id(s) of your newly created device(s) as you will need that for the followin steps. You can later rename or move the devices into specific rooms as you wish.

2) for each of the newly created devices, set a new attribute “openLuup_Ignore” that MUST be set before proceeding further.

Failure to set that attribute will result in a race condition and may make your openLuup system unusable !!!
to do this, run the below code in the AltUI “Lua Test Code” window, replacing deviceid by the relevant device id you obtained in 1) above:

luup.attr_set("openLuup_Ignore", "1", deviceid)

B) on the openLuup system:

1) modify the VeraBridge plugin to instruct it NOT to replicate in openLuup the mirror devices we created on the Vera

Using the tool of your choice (e.g. WinSCP):
a) make a backup of the “L_VeraBridge.lua” file, so that you can undo any mistake later if needed
b) edit the following line of code (it is line 88 in the version of VeraBridge I am using):

	if not (dev.invisible == "1") then

to become:

   if not ((dev.invisible == "1") or (dev.openLuup_Ignore == "1")) then

then save the modified file AND reload openLuup

2) add the following code in either your startup Lua code or (much easier since for now editing lua startup code on openLuup is not very easy) into a lua module that is called on startup… See http://forum.micasaverde.com/index.php/topic,34468.msg254013.html#msg254013

[code]–[[
This code is meant to push certain watched variables on an openLuup system to “mirror” devices on a real Vera

Written by “logread” - free software provided “as is” and to be used at your own risk
Pre-requisite: appropriate mirror devices properly set up on a real Vera, as per separate instructions (including
modified “VeraBridge” plugin and the setup of a new device attribute “openLuup_Ignore” to avoid race conditions

–]]

– USER PARAMETERS: MUST BE EDITED AS APPROPRIATE

local VeraIP = “192.168.99.99” – this is the IP of the Vera on which the mirror device(s) reside
– should be same as in the relevant “VeraBridge” device
local watches = {}
watches[1] = {“urn:upnp-org:serviceId:TemperatureSensor1”, “CurrentTemperature”, 15, 82 }
watches[2] = {“urn:micasaverse-com:serviceId:HumiditySensor1”, “CurrentLevel”, 16, 83 }
watches[3] = {“urn:cd-jackson-com:serviceId:SystemMonitor”, “memoryAvailable”, 17, 85}
watches[4] = {“urn:cd-jackson-com:serviceId:SystemMonitor”, “systemLuupRestartTime”, 17, 85}
–[[ note to the above watches table: for each variable to be mirrored, it needs to include an entry like:
watches[#] = {, , ,}
–]]

– END OF USER PARAMETERS

local http = require(“socket.http”)
local ModuleName = "pushtomirror: "

function url_encode(str) – we need this as some variables to be sent via http might not be compliant with url encoding
if (str) then
str = string.gsub (str, “\n”, “\r\n”)
str = string.gsub (str, “([^%w %-%_%.%~])”,
function (c) return string.format (“%%%02X”, string.byte(c)) end)
str = string.gsub (str, " ", “%%20”)
end
return str
end

function watchvariable(lul_device, lul_service, lul_variable, lul_value_old, lul_value_new)
local mirrordevice = 9999 – fancy device number to avoid lua error if mirrordevice cannot be found
for k in pairs(watches) do
if ((watches[k][1] == lul_service) and (watches[k][2] == lul_variable) and (watches[k][3] == lul_device)) then
mirrordevice = watches[k][4] end
end
local url = “http://” … VeraIP … “:3480/data_request?id=variableset&DeviceNum=” … mirrordevice
url = url … “&serviceId=” … lul_service … “&Variable=” … lul_variable … “&Value=” … url_encode(lul_value_new)
luup.log(ModuleName … "calling " … url) – for debug
local returndata, retcode = http.request(url)
if returndata == nil then returndata = “” end – avoid a crash in logging returndata if error in request
luup.log(ModuleName … retcode … " " … returndata) – for debug
local err = (retcode ~=200)
if err then – something wrong happpened (Vera down, bad parameters)
luup.log(ModuleName … "bad response from Vera " … VeraIP) – for debug
else
luup.log(ModuleName … "good response from Vera " … VeraIP) – for debug
end
end

function watchesregister() – setup the watches
for k in pairs(watches) do
luup.variable_watch(“watchvariable”, watches[k][1], watches[k][2], watches[k][3])
end
end

– register call back functions in the Lua global environment
_G[“watchvariable”] = watchvariable
_G[“watchesregister”] = watchesregister

luup.call_delay(“watchesregister”, 60) – wait 60 seconds so that openLuup finishes its initialization sequence

[/code]
and reload openLuup

This has been tested with my openWeather and openSysMon plugins and 3 target mirror devices on the Vera.

I saw you included in the development branch some placeholder code in VeraBridge for mirroring of selected local openLuup devices on remote Vera. Are you planning to complete this as well in release 8 ? the short term solution I implemented on my system (http://forum.micasaverde.com/index.php/topic,36971.0.html) is definitely not ideal nor simple, though it works well for me :slight_smile:
Happy to contribute if I can help.

I’ve thought about this a fair amount, and it is on the list, but there are some difficulties. Following the outline in your post…

[quote=“logread, post:6, topic:191689”]A) on the real Vera:

1) create the dummy device(s) that will be the mirror(s) and host the mirrored variables[/quote]

On the one hand, I’d like to do this automatically, by selecting a device on openLuup. It is, after all, an openLuup device which you want to mirror. HOWEVER, doing so automatically will cause a reload of the real Vera, albeit only once when the mirror device is created. On the other hand, I’m really not keen on an openLuup system having any impact at all on the Vera it bridges to. Vera manages to reload enough as it is!

I do think, though, that the device type should be the same as the device it is mirroring.

[u]2) for each of the newly created devices, set a new attribute "openLuup_Ignore" that MUST be set before proceeding further[/u].

Failure to set that attribute will result in a race condition and may make your openLuup system unusable !!!

Yes, that’s true, but here’s another problem associated with automatic creation by openLuup: it’s not possible to define, on Vera, device attributes to be created with the device - you have to do this subsequently after you’ve received the new device number (and Vera has reloaded.) Too late! You have a device which you don’t want to mirror but which can’t be distinguished from those that you do. An alternative is to create a special device variable, which you CAN do at device creation.

Either way, whether we end up with an attribute or a variable to flag mirrored devices, it also needs to know which openLuup system created it. It’s perfectly possible to bridge from several openLuup systems to one Vera.

[u][b]B) on the openLuup system:[/b][/u]

1) modify the VeraBridge plugin to instruct it NOT to replicate in openLuup the mirror devices we created on the Vera

Easy enough, of course.

[u]2) add the following code in either your startup Lua code or (much easier since for now editing lua startup code on openLuup is not very easy) into a lua module that is called on startup[/u]

My preference would be for ALL variables on the mirrored device to reflect their openLuup status, and there’s no real difficulty in accomplishing that. This is to make the mirror appear as much as possible to Vera like a real device.

…OR…

There is also another way, which does go against the grain of not installing any additional software on Vera. One could simply write a plugin that monitors any number of remote devices (on openLuup or indeed on another Vera) and has a set of child devices which mirror their status. This approach has the merit of having zero code impact on the openLuup VeraBridge.

So there are some decisions to be made here. I’m not sure this is ready for the next release. Your current solution certainly will continue to work. We would need to fix on the way to ignore the mirrored device.

Thanks Akbooer for this very comprehensive review of the opportunities/obstacles !

I understand all the difficulties around automatic creation/management of remote devices… and I am of the view that manual might be the best approach as a) not many openLuup devices - at least for my needs - need to be mirrored on the Vera and b) this is probably a lot of programming work and mirroring might not be on top of priorities (at least for me, the day Intveltr makes HomeWave compatible with openLuup/Weaved for remote access, the need for mirroring is significantly de-emphasized… but for now I do not know if this is going to happen)

There is also another way, which does go against the grain of not installing any additional software on Vera. One could simply write a plugin that monitors any number of remote devices (on openLuup or indeed on another Vera) and has a set of child devices which mirror their status. This approach has the merit of having zero code impact on the openLuup VeraBridge.
For sure, adding a plugin to the Vera goes against the initial objective :( My approach when getting the Vera to send/fetch something to/from openLuup has been so far to add Lua modules to the Luup startup code on the Vera (that use far less resources than a plugin), but at the expense of "plug & play" capabilities and requiring some advanced knowledge of Lua/Luup.
Your current solution certainly will continue to work. We would need to fix on the way to ignore the mirrored device.
I think this is the best conclusion for now... my obvious recommendation would be to use the extra device attribute I suggested, but obviously you might have a better approach and I'll be happy to align my existing setup ;)

I have thought even further and your reply prompts this idea:

VeraBridge simply has a variable listing local and remote device pairs to be mirrored. The bridge obviously doesn’t clone any Vera devices to which it will be mirroring, and it writes variable updates from the local device(s) to the remote one(s). It doesn’t care whether the remote device is a dummy, specially created, or an existing device, or even if it’s not there.

This just leaves you with the job of creating the dummy device on Vera, and it doesn’t even need a special attribute to distinguish it, since the bridge already knows that. Other openLuup systems which bridge to the same Vera will treat the dummy device as a normal Vera device and clone it into their own environments in the usual way.

This is the simplest approach that I can think of (so far.)

I think this is definitely the most elegant approach indeed for now.

I’ve merged this discussion with the posts on the same topic from the Suggestions thread.

After further experimentation, it seems that mirroring a complete set of variables from a device might be too ambitious for Vera’s own good. There’s a number of situations (reload of either system, or initial creation of the mirror device) when a significant number of variables need updating at the same time. There’s no easy way to do this on Vera except by individual HTTP requests.

So the fall-back situation is very much to follow the approach suggested by @logread and specify each variable that you actually need, individually. I’m struggling with a clean way to do this and have prototyped action calls to the bridge, and played with include files, but it’s still a bit messy if you want a simple view of what the setup is.

This is the one thing that is now standing between us and a Release 8 of the system. Perhaps the best thing would be a custom panel for the bridge in AltUI, but I don’t have the skills for that. Ideas?

I would agree that this would be the nicest approach, but my knowledge of how to do this is nil… Hard coding (like I did in my own setup) is probably not an option for general release.
May be a short term alternative is a text file (rather than json that is less easy to edit, though easier to manipulate) to be dropped in /etc/cmh-ludl ? If the text file does not exists, then VeraBridge ignores mirroring, otherwise it gets all relevant parameters from that file that could have lines in a format like this for each device/variable pair to be mirrored:

<serviceID>, <Variable name>, <openLuup device num>, <target vera device num> ...

simple to code but not super user friendly.

May be another alternative is to add variables to the VeraBridge device, that could be labelled “Mirror1”, “Mirror2”, etc… and use the AltUi device interface to populate these variables like proposed above, followed by a Luup reload… Slightly easier, though still a bit complex for general users.

Thanks for those thoughts. Following (sort-of) your original proposal, and now that Lua Startup can be edited in AltUI, I’m simply proposing that there you have something like:


-- Mirrors syntax:
-- <VeraIP>
-- <Vera deviceId> = <openLuup deviceId>.<serviceId of the variable>.<variable name>
-- ...

luup.attr_set ("openLuup.mirrors", [[
192.168.99.99
82 = 15.urn:upnp-org:serviceId:TemperatureSensor1.CurrentTemperature 
83 = 16.urn:micasaverse-com:serviceId:HumiditySensor1.CurrentLevel
85 = 17.urn:cd-jackson-com:serviceId:SystemMonitor.memoryAvailable
85 = 17.urn:cd-jackson-com:serviceId:SystemMonitor.systemLuupRestartTime
]])

Which can be extended to include other Vera bridges.

So all you’d have to do is edit and reload (editing Lua Startup in openLuup, unlike Vera, does not force a reload.)

Neat… Indeed forgot about startup Lua being now editable !

I’ve updated the development branch VeraBridge to implement exactly this functionality.

Great. I’ll try this out over the week-end on my test VM !

@Akbooer,

Upgraded my test system to openLuup 8RC without any issue… And mirroring works just great ! Many thanks…

My only pending issue is the syncing of house modes, but that’s for another thread

now that I have running some plugins on my verabridge I would like to start offloading those plugins from vera. As I still need pleg I wonder how I will be able create a device property in pleg that refers to a device or variable on the verabridge. I readthrough the above posts a couple of times but I am still unsure wether I have to setup dummy devices on vera which then will be filled by the values from the verabridge or if there is a more elegant way to do this.
The user guide from github (dev branch) states that mirroring requires editing of the startup.lua

-- Mirrors syntax: -- <VeraIP> -- <Vera deviceId> = <openLuup deviceId>.<serviceId of the variable>.<variable name> -- ... luup.attr_set ("openLuup.mirrors", [[ 192.168.99.99 82 = 15.urn:upnp-org:serviceId:TemperatureSensor1.CurrentTemperature 83 = 16.urn:micasaverse-com:serviceId:HumiditySensor1.CurrentLevel 85 = 17.urn:cd-jackson-com:serviceId:SystemMonitor.memoryAvailable 85 = 17.urn:cd-jackson-com:serviceId:SystemMonitor.systemLuupRestartTime ]])
Is this the way to go?
Could you please explain if I have to manually create dummy devices on vera?

[quote=“pls90, post:19, topic:191689”]The user guide from github (dev branch) states that mirroring requires editing of the startup.lua
[…]
Is this the way to go?[/quote]

Yes and No… it’s not a startup.lua file which is involved, but the Startup Lua code on the Misc AltUI pages. The manual is up to date, and since AltUI enables direct editing of the Startup code, then this is very easy to do. When you save an edit to the startup code, you can safely ignore the AltUI warning that there will be a reload - Vera needs this, but openLuup does not.

Could you please explain if I have to manually create dummy devices on vera?

Yes, there was lots of angst about the best way to do this during the design process. In the end, I abandoned any thought of creating a dummy device automatically from openLuup: it would have caused a Vera reload, at the very least (and, goodness knows, Vera does that enough already.) So you really have two choices:

[ol][li]create a dummy device, manually on Vera (easiest through the AltUI interface) it doesn’t need an implementation file, just a device file (although if you did this directly from luup.create_device() you could get away with just a device type which doesn’t even have to exist)[/li]
[li]use an existing device, if it makes sense and doesn’t conflict with any existing device variable.[/li][/ol]

At the moment, the mirrored variable has the same name and serviceId as the local openLuup one, but I’m thinking of extending the syntax in the Startup code to allow you to specify something different.

Ok, I’ll give it a try with my variables from heliotrope.
I agree that an automatic generation of dummy devices is far to complicated.
But how about this:
If the user had some kind of wizard on openluup that lets him pick the object on the verabridge wich he wants to mirror and then the wizard determines which device type and hence device file is needed and then creates the device on vera.
For example my use case would be:
I need the heliotrope variables ‘azimuth’ and ‘altitude’ mirrored. So I would start the wizard, pick the ‘heliotrope’ from a list of all devices on verbridge and be presented with a list of all variables from ‘heliotrope’. I then would check all variables needed. Finally clicking on ‘generate devices’ would create all needed devices on vera.
What do you think?