I have three temperature sensors, and I want to calculate the average value. A virtual device should receive this average value. Am I on the right track? How do I assign a variable to a virtual device?
I'm doing the same with three indoor temperature sensors, but in a slightly easier way just by using the Average Temperatures found at official example-apps code: HubitatPublic/example-apps/averageTemp.groovy at master Ā· hubitat/HubitatPublic Ā· GitHub
Very much so on the right track! Of course, should you ever add more sensors, your rule will grow geometrically, so you may want to consider using WebCore instead (which lets you perform complex calculations in a single line, and includes built-in math functions that take multiple inputs such as average, variance, etc.).
As for assigning the result from RM into a virtual temperature device, use "Custom Action":
I've spent way too much time on this, but it finally works! There's just a small correction left. Does anyone have any suggestions on how to improve this routine? I'm eager to learn everything about RuleMachine
Thanks to everyone who helped me!
Just something to consider. Depending on the importance of that average, I would also suggest that you check for valid temperatures and either ignoring an out of bound value sensor or exiting the rule without a new average. I have a 30+ devices that send temperature, and at times of teetering on low battery or other unknown reasons, a ridiculous value gets sent, such as 45727 degrees. The high average temperature in the house then ends up triggering the air conditioning and fans and emergency alerts to our phones.
It will definitely add length to your rule. Once you get one long rule down, then you can simply clone it for other averages.
I've used BPTworld's Averaging Plus. No longer maintained, but my understanding is you can still manually download the bundle and install it. Works great and very simple to use.
Everything looks correct, but if you're aiming for "coding compactness" (hardly necessary, since the per-line execution or storage overhead of Rule Machine rules is negligible), I'd only comment:
- The variables in use here could be local RM vars instead of Hub Variables;
- You only need a single variable (e.g. AvgTemp) and let it do all the work... set = 0, iteratively sum itself plus the three other values, divide / 3, voilĆ !
- As @neerav.modi correctly advises above, especially when "living environment" real-world settings are involved (such as HVAC), it always pays to check values for valid lower and upper bounds.
There are a few apps out there that will do that for you. I realize your are trying to learn and I actually created a RM rule to do that myself at one point, but an app allows you to setup multiple averaging devices much easier.
The app posted below is one @bravenel created some time ago that works well. I believe there is one in HPM by @csteele as well. Others as well, as posted above. The app below along with averaging lets you assign more weight to one device over another. So I ended up switching to it. I also have a version that does humidity sensors, I modified the one below
definition(
name: "Average Temperatures",
namespace: "hubitat",
author: "Bruce Ravenel",
description: "Average some temperature sensors",
category: "Convenience",
iconUrl: "",
iconX2Url: "")
preferences {
page(name: "mainPage")
}
def mainPage() {
dynamicPage(name: "mainPage", title: " ", install: true, uninstall: true) {
section {
input "thisName", "text", title: "Name this temperature averager", submitOnChange: true
if(thisName) app.updateLabel("$thisName")
input "tempSensors", "capability.temperatureMeasurement", title: "Select Temperature Sensors", submitOnChange: true, required: true, multiple: true
paragraph "Enter weight factors and offsets"
tempSensors.each {
input "weight$it.id", "decimal", title: "$it ($it.currentTemperature)", defaultValue: 1.0, submitOnChange: true, width: 3
input "offset$it.id", "decimal", title: "$it Offset", defaultValue: 0.0, submitOnChange: true, range: "*..*", width: 3
}
input "useRun", "number", title: "Compute running average over this many sensor events:", defaultValue: 1, submitOnChange: true
if(tempSensors) paragraph "Current sensor average is ${averageTemp()}Ā°"
if(useRun > 1) {
initRun()
if(tempSensors) paragraph "Current running average is ${averageTemp(useRun)}Ā°"
}
}
}
}
def installed() {
initialize()
}
def updated() {
unsubscribe()
initialize()
}
def initialize() {
def averageDev = getChildDevice("AverageTemp_${app.id}")
if(!averageDev) averageDev = addChildDevice("hubitat", "Virtual Temperature Sensor", "AverageTemp_${app.id}", null, [label: thisName, name: thisName])
averageDev.setTemperature(averageTemp())
subscribe(tempSensors, "temperature", handler)
}
def initRun() {
def temp = averageTemp()
if(!state.run) {
state.run = []
for(int i = 0; i < useRun; i++) state.run += temp
}
}
def averageTemp(run = 1) {
def total = 0
def n = 0
tempSensors.each {
def offset = settings["offset$it.id"] != null ? settings["offset$it.id"] : 0
total += (it.currentTemperature + offset) * (settings["weight$it.id"] != null ? settings["weight$it.id"] : 1)
n += settings["weight$it.id"] != null ? settings["weight$it.id"] : 1
}
def result = total / (n = 0 ? tempSensors.size() : n)
if(run > 1) {
total = 0
state.run.each {total += it}
result = total / run
}
return result.toDouble().round(1)
}
def handler(evt) {
def averageDev = getChildDevice("AverageTemp_${app.id}")
def avg = averageTemp()
if(useRun > 1) {
state.run = state.run.drop(1) + avg
avg = averageTemp(useRun)
}
averageDev.setTemperature(avg)
//log.info "Average sensor temperature = ${averageTemp()}Ā°" + (useRun > 1 ? " Running average is $avgĀ°" : "")
}
Hi, it's me again! Can someone help me? Iāve been trying to search and test, but I canāt figure out how to do this. I want to assign sum = Variable1 + Variable2 + Variable3
in a single line, not as I currently have written in a three-line routine. I hope you understand what I mean. It's the same routine Iāve done, but I want to make it cleaner and more compact. Iāve received some answers already, and Iām very grateful for them, but itās a bit hard to find in RuleMachine.
I'm not aware where you can do all of that in one line, in Rule Machine. And that's ok. Optimizing that much doesn't have any beneficial effect on hub performance.
If you want to save a line, instead of setting SumValue to 0, set it to one of the sensor temps.
Another optimization could be to combine the last two lines of your original Actions by setting Bedroom average to Sumvalue / 3 instead of going through the Average Temp local variable.
Edit: Ignore the following because variable math can't add a sensor value to the existing value: Further optimization is to set the SumValues to each sensor instead of first assigning them to the local temp1, temp2, and temp3 variables.