Author Topic: Save state between scenes  (Read 3865 times)

Offline AndersMalm

  • Newbie
  • *
  • Posts: 19
  • Karma: +3/-3
Save state between scenes
« on: November 05, 2018, 05:31:22 am »
I have two scenes one that runs when my Movie Projector starts and one when it shuts down.

The starting script I will turn off all lights that are on could be done by polling

Code: [Select]
luup.variable_get("urn:upnp-org:serviceId:SwitchPower1", "Status", deviceId) and if its on call

Code: [Select]
luup.call_action("urn:upnp-org:serviceId:SwitchPower1","SetTarget", {newTargetValue = "0"}, deviceId)
To turn it off

Problem is I need to save an array with the deviceIds that was on. And then from the projector shut down scene I need to access this array and turn the lights back on.
How can I save state between scenes? It does not need to survice power failure to controller etc.

Thanks, Anders

Offline AndersMalm

  • Newbie
  • *
  • Posts: 19
  • Karma: +3/-3
Re: Save state between scenes
« Reply #1 on: November 05, 2018, 07:16:18 am »
This does the trick

First the script that turns off lights, devices is a list of ids. A global array movieLights  is also defined and all turned on lights in the devices array are pushed to it.

Code: [Select]
local devices  = {19}
movieLights  = {}

for i, device in ipairs(devices) do
   if luup.variable_get("urn:upnp-org:serviceId:SwitchPower1", "Status", device) == "1" then
      table.insert(movieLights, device)
      luup.call_action("urn:upnp-org:serviceId:SwitchPower1", "SetTarget", {newTargetValue = "0"}, device)     
   end
end

And here is the script that resumes the lights
Code: [Select]
for i, light in ipairs(movieLights) do
   luup.call_action("urn:upnp-org:serviceId:SwitchPower1", "SetTarget", {newTargetValue = "1"},  light)     
end

Offline Quixote

  • Sr. Member
  • ****
  • Posts: 335
  • Karma: +16/-34
Re: Save state between scenes
« Reply #2 on: November 07, 2018, 02:22:33 am »
This seems ridiculously complicated. Every time I look at one of these scripts I feel like I'm semi-retarded.
I was wondering if you could help me grasp this as it's been so long since I did any real Lua scripting (like 10 years or something). I have one project that I'm currently trying to accomplish, though it seems that the shortfalls of the Vera may prevent any progress whatsoever. I'd like to cycle through scenes using tap events and tap-and-hold events on a Wallmote Quad. Unfortunately, it seems that no events are registered even when I'm 10 feet from the vera with the device.
In any case, it would be nice to figure out the coding in the event that the thing starts working as my Homeseer motion sensor did out of the blue, 2 days after I set it up.
My "Karma" has been modified by 2 or 3 douchebags that didn't like that I criticized the plugin that they worship. I'm not actually a bad person. (I guess I'm "Chaotic Neutral").

Offline rigpapa

  • Beta Testers
  • Hero Member
  • *****
  • Posts: 758
  • Karma: +115/-1
Re: Save state between scenes
« Reply #3 on: November 07, 2018, 08:09:59 am »
This solution also won't work across a Vera reload or reboot, if that happens while you're watching a movie. To address that, you need to save the movieLights table to state somewhere:

Code: [Select]
-- Save the movieLights table in my private service on device 99 (projector?)
luup.variable_set( "urn:mydomainname-com:serviceId:MyServiceName", "MovieLights", table.concat( movieLights, "," ), 99 )

...

-- Get the movieLights table from my private service
str = luup.variable_get( "urn:mydomainname-com:serviceId:MyServiceName", "MovieLights", 99 ) or ""
movieLights = {}
str:gsub( "([^,]*),", function( m ) table.insert( movieLights, tonumber(m) ) return "" end )
if str ~= "" then table.insert( movieLights, tonumber( str ) ) end

This saves the table as a comma-separated list (string), but it's kind of a pain to undo that, as you can see. It simplifies the code to use JSON, at a small expense of more memory use to do the module loading:

Code: [Select]
json = require("dkjson")
-- Save the movieLights table in my private service on device 99 (projector?)
luup.variable_set( "urn:mydomainname-com:serviceId:MyServiceName", "MovieLights", json.encode(movieLights), 99 )

...

-- Retrieve the movieLights table
str = luup.variable_get( "urn:mydomainname-com:serviceId:MyServiceName", "MovieLights", 99 ) or "{}"
movieLights = json.decode( str ) or {}

Note that this basically ignores any errors that might pop up in JSON decoding, but if the stored value is only touched by this code, there should never be any such errors. If an error does occur, this code just produces an empty table (no crash).
Author of Reactor, DelayLight, SiteSensor, Rachio, Deus Ex Machina II, Intesis WMP Gateway, Auto Virtual Thermostat and VirtualSensor plugins. Vera Plus w/100+ Z-wave devices. Vera3 sandbox.

Offline AndersMalm

  • Newbie
  • *
  • Posts: 19
  • Karma: +3/-3
Re: Save state between scenes
« Reply #4 on: November 08, 2018, 01:10:18 pm »
This solution also won't work across a Vera reload or reboot, if that happens while you're watching a movie. To address that, you need to save the movieLights table to state somewhere:

Code: [Select]
-- Save the movieLights table in my private service on device 99 (projector?)
luup.variable_set( "urn:mydomainname-com:serviceId:MyServiceName", "MovieLights", table.concat( movieLights, "," ), 99 )

...

-- Get the movieLights table from my private service
str = luup.variable_get( "urn:mydomainname-com:serviceId:MyServiceName", "MovieLights", 99 ) or ""
movieLights = {}
str:gsub( "([^,]*),", function( m ) table.insert( movieLights, tonumber(m) ) return "" end )
if str ~= "" then table.insert( movieLights, tonumber( str ) ) end

This saves the table as a comma-separated list (string), but it's kind of a pain to undo that, as you can see. It simplifies the code to use JSON, at a small expense of more memory use to do the module loading:

Code: [Select]
json = require("dkjson")
-- Save the movieLights table in my private service on device 99 (projector?)
luup.variable_set( "urn:mydomainname-com:serviceId:MyServiceName", "MovieLights", json.encode(movieLights), 99 )

...

-- Retrieve the movieLights table
str = luup.variable_get( "urn:mydomainname-com:serviceId:MyServiceName", "MovieLights", 99 ) or "{}"
movieLights = json.decode( str ) or {}

Note that this basically ignores any errors that might pop up in JSON decoding, but if the stored value is only touched by this code, there should never be any such errors. If an error does occur, this code just produces an empty table (no crash).

Good idea! You could also read the list of lights you want to be affeced the same way, that way you can edit the variable list for that device instead of editing the script

Offline BrownDrain3

  • Newbie
  • *
  • Posts: 1
  • Karma: +0/-0
Re: Save state between scenes
« Reply #5 on: November 08, 2018, 01:51:43 pm »
I had the same problem. Thank you)

Offline AndersMalm

  • Newbie
  • *
  • Posts: 19
  • Karma: +3/-3
Re: Save state between scenes
« Reply #6 on: November 09, 2018, 04:07:06 am »
This seems ridiculously complicated. Every time I look at one of these scripts I feel like I'm semi-retarded.
I was wondering if you could help me grasp this as it's been so long since I did any real Lua scripting (like 10 years or something). I have one project that I'm currently trying to accomplish, though it seems that the shortfalls of the Vera may prevent any progress whatsoever. I'd like to cycle through scenes using tap events and tap-and-hold events on a Wallmote Quad. Unfortunately, it seems that no events are registered even when I'm 10 feet from the vera with the device.
In any case, it would be nice to figure out the coding in the event that the thing starts working as my Homeseer motion sensor did out of the blue, 2 days after I set it up.

It doesnt help that Lua is a pretty backward language :D In C# a foreach loop (Iterate over every item in a collection)

Code: [Select]
foreach(var item in items)
{
}

Translates to this in lua
Code: [Select]
for i, item in ipairs(item) do
end

Or adding a item in C#
Code: [Select]
items.Add(myItem);
Translates to some static method mumbo jumbo
Code: [Select]
table.insert(items, myItem)
Though, any language support it better than no language support! Python would have been a better choice though in my own opinion

Offline rigpapa

  • Beta Testers
  • Hero Member
  • *****
  • Posts: 758
  • Karma: +115/-1
Re: Save state between scenes
« Reply #7 on: November 09, 2018, 11:35:34 am »
Lua is purpose-designed as an embedded language. It makes some syntactic trade-offs to keep implementation cost and resouce demand low, but it's still quite powerful, once you get to know it. It's a far more appropriate choice for a platform like this than either C# or Python, IMO, especially if you look at what most people do on the platform (write short script-like stubs to do simple tests and actions). Vera didn't do the best job of building their Luup interface into it, or evolving it over the years, and as a very active developer in this community (and separately many other projects in C/C#/C++, Python, Java, JS family and others), I have many more issues with that than I do with Lua itself.
Author of Reactor, DelayLight, SiteSensor, Rachio, Deus Ex Machina II, Intesis WMP Gateway, Auto Virtual Thermostat and VirtualSensor plugins. Vera Plus w/100+ Z-wave devices. Vera3 sandbox.

Offline AndersMalm

  • Newbie
  • *
  • Posts: 19
  • Karma: +3/-3
Re: Save state between scenes
« Reply #8 on: November 09, 2018, 12:03:41 pm »
Lua is purpose-designed as an embedded language. It makes some syntactic trade-offs to keep implementation cost and resouce demand low, but it's still quite powerful, once you get to know it. It's a far more appropriate choice for a platform like this than either C# or Python, IMO, especially if you look at what most people do on the platform (write short script-like stubs to do simple tests and actions). Vera didn't do the best job of building their Luup interface into it, or evolving it over the years, and as a very active developer in this community (and separately many other projects in C/C#/C++, Python, Java, JS family and others), I have many more issues with that than I do with Lua itself.

Thanks to the Roslyn project you can purpose fit C# for anything. But I dont have a problem with Lua, as a developer I can use any language. But Lua does have its quirks. :D

edit: also pretty interesting how  Lua handles array capacity :D https://stackoverflow.com/questions/124455/how-do-you-pre-size-an-array-in-lua
« Last Edit: November 09, 2018, 12:37:52 pm by AndersMalm »