Not sure if this a Groovy question or Hubitat specific. I want to have global variables that any method can read / write. I put this in top of my code:
def validUserCode = false
def entryDelayRunning = false
If I try to read them within a method, I get a null
import groovy.transform.Field
@Field entryDelayRunning = false
1 Like
Do you need the data to persist across different executions of your app/driver or be re-initialized each time? What about reboots? Do you want it to be shared among all instances of your app or unique to each? The above is one solution; there are others, including state
(a traditional option for this in Hubitat, perhaps better documented), depending on your needs.
1 Like
Not worried about Re-initialize, not sharing across instances, not worried about re-boots. Can you give me an example of "state"?
@thebearmay Thanks for the response. This works to read the variables in the methods, but I cannot write to them.
import groovy.transform.Field
@Field entryDelayRunning = false
The state
object is a Map
that is available to every app (and driver)--no special setup required on your side. Its intent is to provide a space to store values that need to persist between executions of the same app (or device). Incidentally, it is also effectively global within your app/driver. Each app/driver has its own state
, i.e., it is not shared across all instances that use the same app or driver code.
You can't store arbitrary objects in state, but any of the common data types (String
, Integer
, BigDecimal
, etc.--not things like a DeviceWrapper
reference, for example) should work. To use: anywhere in an app, you can do something like state.x = "y"
and recall that value later with state.x
or any other method you might use on Map
s.
That being said, if you don't care about persisting the values, perhaps you don't need state
, and a Field
variable might be lower overhead (though a bit more work to set up on your part). It might be better to state your specific use case, however, in case the nature of Hubitat app and driver lifecycles isn't apparent at this point in your development. Another thing you could do is just pass the values between methods calls in your app (or re-think how whatever you're doing is done in the first place)--a Field
whose value doesn't persist across different executions of your code wouldn't give you much over that, I don't think.
You are talking to amateur coder! You lost me on "DeviceWapper", lol. I am used to being able to declare a Global variable at the start of my code, and them being able to write or read to that variable in any Method or Function. No persistence at all. I hear what you are saying about passing variables to the methods.
As with your previous thread, I'd suggest that a clear, minimal but functional code snippet demonstrating you want to do or what isn't working and why will probably get you the best help the fastest. Alternatively, you can just play around with the ideas above to see if any are what you're looking for. (Or if you're new to both the platform and programming, I might suggest first seeing if a built-in app suits your needs, with Rule Machine being the most powerful and capable of creating arbitrarily complex automations without real "coding" at all--but it's also not where I'd start unless nothing else meets your needs. Maybe a description of your automation goal would be even more helpful?)
That being said, from your description in the latest post, I think there are two differences at play compared to "global variables" you might be used to in other programming languages: first, Groovy itself, where any "top-level" code in a script gets shoved inside a "hidden" method and thus is not available to other methods (presumably because all Java code exists inside a method, per Java language design, and Groovy is designed to be easily interoperable with Java)--unless you elevate it to class/script-level status with the Field
annotation, as another poster suggested.
Second is the lifecylce of Hubitat app (or driver) code, which usually just wakes up in response to some subscription (device event, schedule, etc.), executes the handler method, then goes back to sleep--so any variables you've modified will be lost unless you've persisted them into state
(one I idea I mentioned above) or stored them as a static Field variable (which will not be re-initalized on every execution but rather only when new code is saved or the hub is rebooted...and maybe as a result of undocumented cleanup, but I don't think I've seen that happen). But static Fields pose an additional challenge that they are shared across all instances of an app or driver that share the same code, so you generally would want to make those fields a Map
(and generally also a concurrent-friendly one) and index into it by app or device ID.
This might be information overload. A specific example, again, would probably get you the best advice.
2 Likes
Let me add to the confusion a little
Type |
Setter |
Getter |
Field |
inline, i.e. = |
normal usage |
Hub Variable |
this.setGlobalVar(varName, varValue) |
this.getGlobalVar(varName).value |
Settings |
Input statement or updateSetting("settingName",[value:settingValue,type:"settingType"]) |
normal usage |
State |
state.varName =… |
normal usage, i.e. state.varName |
1 Like
@thebearmay Thanks for the input, the more info, the better! I wound up using atomicState. Dont't fully understand it, but it works
@bertabcd1234 Again, thanks for all the help. In this post, and others. Yes, I am well versed with the rule machine. I have three Hubs total, one here, two up at the lake property. Plenty of rules working well. This is more about learning. My code experience is writing a large business data app using vb.net with an SQL backend. Very different world then java / groovy! I decided a great way to learn is writing an app to replace the HSM. So far. we are making progress