Going to try my first actual code for HE. And I don't even know if an app or a driver is the right structure for it (or if it matters much).
Phase 1 will have a configured (or hardcoded; specific to what I need) URL, a regular expression to apply to the data returned by that URL, and the name of a switch to turn on if the regexp matches (or off if the regexp does not match; usually it'll be a virtual switch that I then use in RM rules).
(Phase 2 might be an app that lets me configure multiple sets of URL, regexp, variable. Maybe polling frequency for each rule, too.)
It will poll the URL regularly (hardcoded at first; I guess it should be configurable per-URL in phase 2), and set the variable each time as appropriate.
So, I think this is probably an app? But what do I know. I think this is simple enough for a first try.
(The immediate use-case for this is to scrape from my local city's web page information about whether a "snow emergency" is in effect. That means special parking rules so the streets can be plowed to the edge. I want to include this along with weather alerts and any household problems, fire, intruder, flood, the usual stuff, in notifications conveyed via Inovelli LED bars and a few strategically located RGBW bulbs for real emergencies.)
(I can write an article on the problems of "screen-scraping", which is what this is. If you can find an actual web API presenting the information you want, that would be better. Note that this app can also work with an API; it just makes the regexp probably simpler, and the whole thing more reliable since the format won't change on the whims of designers.)
If I get this working I'll be pleased to release it, for whatever value it may have to others.
I'd suggest an 'app' as what you seem to be building is a utility to control other devices, so I don't think philosophically it's a driver even though it sounds like you could do all of this in a driver.
As mentioned above, you'd need an app to do this; drivers can't directly control other devices (with parent/child devices being an exception but probably not something you want to do here). In an app, you have to prompt the user to choose a device, then use that "reference" to a device to run whatever commands on it--so to be extra clear here, you'd ultimately not be looking for a switch "by name" but by user input, like you've undoubtedly seen in other apps you've used on Hubitat so far (e.g., "choose a device to do X...").
This is the first mention I've seen of "the variable" and don't know what it's referring to, but if you are thinking of a device attribute (something like you might see under "Current States" on a device page), then this would indeed need to be a device, maybe one with a custom attribute like isAlert that can be true or false (actually, I don't think Booleans are a valid data type for attributes, so this would either have to be a string or some other mechanism, but same idea).
But something else you could do: leave the custom app and a virtual switch out of this and just make your idea be a driver that is an (effectively virtual) switch, then set the switch attribute to on when your conditions are met and off when not. I think all of what you're asking should be do-able in either an app or driver (both have access to the same HTTP methods you'll need to get this data), so either should work, with the difference being just a matter of how you want it to be implemented. But this way, the user wouldn't need to specify a virtual switch; your custom code could just be a driver that implements "Switch" capabilities directly. The resulting device(s) could then be used in other apps by the user as desired.
Sorry about "the variable", I was still thinking of a configured virtual switch. Making this a device, and making it be the actual switch, is an interesting idea, it seems to make it easier for the user to set up.
I agree in some cases. In others, I'm not really sure, since you have a lot of control over the UI of an app but almost nothing over the UI of a driver, so you'd have to have documentation telling users how to set the preferences or whatnot (e.g., "put this in for the URL setting," etc.) that you might be able to step people through better in a more flexible app--but of course, you'd probably have to documented it either way and people should read it either way. A driver may be simpler to write, however, and possibly easier to set up for people who do read (no need to mess with an app and separate device).
If you're just getting started writing Hubitat Apps and Drivers, I would probably start with making this a simple driver. Keep it simple to begin with, with just a time based schedule to read the URL and then parse the response. Use a relatively short timeout, like 10 seconds on the httpGet() call. This will prevent the hub from waiting for a long time on a reply that may never come (e.g. internet is down.) Also, keep the polling frequency reasonable, like once every 4 hours, since this data is likely to rarely change.
If you do decide to get a little fancier later on, please know that an App can very easily create a child device to pass the status information into. I very much prefer this design, versus having to have the user manually add a virtual device, and then select it from within the app.
I have written many Drivers, but only a few Apps. So I may be a little biased... I especially like Parent/Child (Composite) drivers.
In the longer run I may want fancy poll scheduling -- there's a 6pm deadline for them to declare a snow emergency, which takes effect at 9pm. So, polling shortly after 6 is important. But polling frequently earlier in the day is not important. Also, I could cut the frequency down a lot once they declare an emergency -- they never undeclare them, they just run 3 days until they're finished.
And that's the sort of detail that's completely city-dependent, and why I'll be surprised if there's a general solution to the snow emergency notification question. Although I've been thinking of notations to specify weird and lumpy polling schedules like that; that could some day go into a general-purpose simple scraper device.
If I do it as a device -- then the device could just handle one URL? And if I needed to do 3 I could just create 3 instances of the device? That sounds a lot easier for the user as well as for the developer.
You could have a driver poll as many different URLs as you'd like. You could store the pertinent information into custom attributes, if you like. I would advise you to look at some of the community developed 'weather' drivers as examples of what is possible.
So...attributes of a device are changed by sendEvent, including internally? I think I'm understanding this by reading existing drivers. This isn't a completely unfamiliar way to do things, I did spend a year on a contract at Siemens using industrial control software that thought rather that way. By changing the defined attribute through the explicit sendEvent call I'm letting anything subscribed to changes to that attribute know about the change.
Is that right?
Could I have found that in the online documentation at Hubitat?
Including a Capability will automagically define specific attributes and commands for the device. Including a standard capability, will implicitly declared the appropriate commands and attributes defined for that capability.
You can also add custom commands and custom attributes. These must be explicitly declared in the metadata section of the driver, and then implemented.
Are schedule()/unschedule(), runIn(), and the runEvery10Minutes() family standard functions that I can use in my driver? I see them called, but I find zilch if I search the developr docs for "runevery" for example.
(I think, just based on what's passed to it, that schedule() is using crontab format for when to run the function specified? Kind of neat!. Is "unschedule" actually related, and what exactly does it get rid of? Everything this driver scheduled? Or this instance of the driver? Or can the driver schedule only one thing?)
Do drivers have multiple instances, or something? I know something like that happens since I can define any number of virtual switches; they all run on the same driver, right, just as a pile of Inovelli switches all run on that driver?
Yep, you’re a very quick study! Calling unschedule() with no arguments will remove all scheduled events for that device. You can pass in the name of the function to only unschedule those related scheduled events, IIRC.
The Classic ST Documentation is a decent reference guide as well, since Hubitat is mostly ST Classic compatible.
I vary wildly in how fast I catch on to new environments, especially without documentation. But...I've been in software professionally since 1969, started learning about it a year before that, so by now I've seen most things! That either helps or hurts, sometimes I'm expecting things no longer true (like documentation ), but I've seen things other than straight-forward procedural code rather a lot and that certainly helps when meeting new varieties of that.
I didn't recognize the language name "Groovy", I was very pleased to find it's something real, not a local proprietary thing.
Ah, the secret previous-version manual! Thanks, I'll check (and not blame anybody for the cases where things aren't still the same!).
(With my social group, "Classic ST" is also known as "ToS", and means the original 3 seasons of Star Trek, back in the 60s. But I know what you mean using it here.)
It's actually kind of an accident that I'm on HE instead of a Samsung Smart Things hub. They were both among my top shopping choices -- and when it came time to order nobody had the Samsung. Part of me said "clearly that's the good one, everybody bought that one", and part of me said "why wait?". Enjoying HE well enough so far, but lack of documentation is a recurring complaint. (I did also have a preference for the cloud-free possibilities of HE.)
So what does one have to put in the impurtUrl field of the definition to get importing from gitHub to work? The obvious thing, a URL that actually leads to a page giving just the code, doesn't work. But no error is given, it just doesn't replace the code.
You can look at an example from one of my drivers. The “importUrl” is case sensitive, IIRC.
I chose this driver as it routinely wakes up and performs an httpGet to a local device on my network. It then parses the returned string and updates multiple child devices that it automatically creates as necessary. It is similar to what you’re trying to build.
Your string works in my browser but not in HE, exactly the same as mine (and mine came from copying out of the browser address bar, so I'm sure the casing is right).
So am I somehow misunderstanding what that field does, or how the "import" button on the driver page works, or something?
On the driver page, when I click import, I get a popup with the value of importUrl pre-loaded, but I can overwrite it with whatever. But when I click the action button in the dailog box nothing happens?
Ah, I'll steal more from your driver then . Probably tomorrow, I'm running down for tonight.