I’m using the HTTP binding with JSONPATH on the channel to retrieve information from a flaky weather station. It often goes offline, but the API carries working on fine, just the data doesn’t change, including the last updated timestamp.
I enabled expirations on the items (e.g. temperature), but of course, that never expires, because there is data being returned, and that item has no idea about the timestamp.
What’s the best practice way of dealing with this issue? My initial thought it that I’ll need to write a custom transform step in the channel that checks the timestamp - but I’m not sure how I then put that channel into a faulted state etc (whatever causes the expiration timer to work).
If I understand correctly, you don’t want openHAB to “continue” using an outdated value for an item, if the corresponding input field is offline? I don’t have that issue, but it seems, the http binding works with “cached” information in that case? Perhaps you have to dig deeper, I’d expect the binding to not update items, if the http-query throws an error and/or the JSON doesn’t match.
but apart from that: I can think of two ways to achieve that:
write a openHAB rule, which populates the items from the weather station
handle the item updates via node-Red, which won’t send updates, if it detects the station as offline
The operator of the station uploads their content to a third-party API, which is reliable. But the JSON isn’t updated when it’s not reporting, it keeps the last reported data, along with the timestamp, e.g.
The HTTP binding isn’t caching or failing to retrieve that, it’s just the API no longer has up-to-date data, and the JSONPATH happily updates my temperature item with 1.5, obviously irrespective of the “updated” timestamp.
I need to conditionally update the item based on the JSON processing. I’m just not sure the best way to tackle that.
ah! Now I understand. the http-request is always possible and the JSON is always correct, but the values are outdated!
Yes, in that case, you’ll have to write your own logic in a OH rule or with an external checker. Both can only send updates to your items, if the “updated”-flag is current.
I don’t know of a conditional update within a channel-defition using JSONPATH, but perhaps that’s possible?
But: What do you gain from that? I don’t know your usecase, but perhaps its easier to insert a rule, if the “updated”-item is old.
in the end: your source does not sending values for a period of time, but you can’t guess them, do you?
What I don’t like the idea of is having to have an intermediary item. I don’t think I can have a rule off the HTTP thing to process the data and allow through to the item. So I need an interim item cluttering up my model and properties and another one with the actual value.
I guess the advantage of doing it at the Thing is that’s cleaner and uses the Expire settings - I’m just not sure how to get a channel to fault and not update.
what you could do is to calculate the transformation in a script - for each channel.
The script then knows the state of the “update”-item (as it comes within the JSON) and you could then easily return the desired values for “update within time range” and “update too old”.
But again: I’m still not sure regarding your use case. What do you want to achieve? Do you rely on current values? Do you want to “calculate” the weather information, if the timestamp is too old? …? Perhaps there’s a way easier way for your use case.
I’m logging temperature etc, I don’t want to view in graphs stale information from persistence. I’ve got a few different stations that I average out in a group, but having one with stale data will throw off the averages.
I see on that link that null return will probably achieve what I want, so I can take the complete JSON doc in, check the timestamp before returning either the temp (or whatever), or null if it’s too old. I’ll give that a whirl.
my suggestion still: Use your own weather station!
They’re quite affordable and realiable. I’ve got one of these running 4years with the same battery and still works as intended:
You can configure Expire to only reschedule itself on changes. If the weather station goes offline, presumably the Item’s states are just being updated, not changing.
Just check “ignore state updates” and it will timeout the Item even if it’s continuing to be updated to the same value.
You’ll have to be careful to set a long enough expire so the Item doesn’t reset just because the weather isn’t changing that much.
An Item like that shouldn’t be in your model in the first place.
You should not put every Item into the model. Only those your end users will care about.
The easiest approach would be to just tell expire to ignore updates.
The next easiest would be to go down the path you are going now and write a JS transform that returns null if the timestamp in the message is too old. Chain that to your JSONPATH and the message will be thrown out entirely if it’s too old.
A rule can be configured from this template to call another rule you write if an Item remains the same value for too long a time. The rule you write can take remedial actions based on that fact (send an alert, turn something on/off, disable a Thing, etc).
I use one instance of this rule template to get an alert when a service goes offline, another when a sensor stops reporting, yet another for alerts when the doors are left open, another for when the humidity gets too low, another to drive the humidifiers, and another to get an alert when the motion sensor at my dad’s house doesn’t detection motion for too long a time.
configuration: {}
triggers: []
conditions:
- inputs: {}
id: "2"
configuration:
type: application/javascript
script: >
var equipment = actions.Semantics.getEquipment(items[alertItem]);
var statusItem = items[equipment.name+'_Status'];
if(equipment === null || statusItem === null) {
console.warn(alertItem + ' does not belong to an equipment or equipment doesn\'t have a Status Item!');
false;
}
else {
var statusItem = items[equipment.name+'_Status'];
console.debug('Sensor status reporting called for ' + alertItem + ', equipment ' + equipment.label + ', is alerting ' + isAlerting + ', and is initial alert ' + isInitialAlert);
// Sensor is back online Sensor went offline
(isInitialAlert && statusItem.state == 'OFF') || (!isInitialAlert && statusItem.state != 'OFF');
}
type: script.ScriptCondition
actions:
- inputs: {}
id: "1"
configuration:
type: application/javascript
script: >
var {alerting} = require('rlk_personal');
var logger = log('Sensor Alert');
var equipment = actions.Semantics.getEquipment(items[alertItem]);
var statusItem = items[equipment.name+'_Status'];
if(!isInitialAlert && statusItem.state != 'OFF') {
statusItem.postUpdate('OFF');
alerting.sendAlert('Offline: ' + equipment.label + ' has stopped reporting', logger);
}
else if(isInitialAlert && statusItem.state != 'ON') {
statusItem.postUpdate('ON');
alerting.sendAlert('Online: ' + equipment.label + ' is back', logger);
}
type: script.ScriptAction
What it does is if an Item doesn’t change for 15 minutes it will call my alert rule. My alert rule pulls the Item’s semantic model, sends an alert and sets a status Item to OFF indicating the Equipment is offline. When the Item changes again, the rule is called again and the status Item is changed back to ON and an alert is sent indicating the Equipment is back online. Of course, there is a DND period so I don’t get these alerts at night.
As ever, really helpful post, thanks!
I have tried this approach, and indeed I’m getting the value unset, but it seems that this doesn’t work with persistence (rr4j):
It’s never going to work with rrd4j in any approach. NULL and UNDEF never get saved to the database and the way rrd4j works something has to be saved every minute or else the entire database breaks. So rrd4j is going to keep saving the last value until the Item changes to a new value that can be saved. You are never going to get gaps in your charts with rrd4j to indicate no data. It just doesn’t work like that. If you need that you need to use some other database that doesn’t require a valid number to be saved every minute.
Alternatively you can have expire update the Item to some number to indicate no data, but what the number should be isn’t so easy for weather data. 0 is a perfectly valid temperature but -50 is going to throw the y scale on your charts way off.
Switching to any other DB except MapDB (which only stores the most recent value) would work. The every minute requirement is specific to rrd4j and it’s tied to how it decimates the data as it ages and is what allows it to never grow in size no matter how long you store data in it.
How does one control whether an item is in the model or not? When I add items without using the model, they still appear, just cluttering up the root level.
Don’t use semantic tags for that Item. You have full control over what is and is not in the model.
There is a checkbox to “show non-semantic” on the model page and Item selection dialog. Uncheck that and you will only see Items that are part of the semantic model on those pages.
Items that do not have semantic tags will not appear on the overview pages automatically.
The Items Settings page is not semantically aware. It will always show all Items.
Note that a non-semantically tagged Item can be put into a semantically tagged Group (i.e. Equipment or Location). This does not make the Item a part of the model but it can be helpful to find those Items when “show non-semantic” is checked.