Magic to grab temp and put in generic thing

Hey guys, i have a system here i need to do a very simple thing, but i literally suck with magic. Perhaps someone can help.

I built a machine that i put in a datacenter that measures 2 temperature probes, i made a simple webpage on it that will display the temps in this format: 85:79 (With 85 being the temp of probe1 and 79 being the temp of probe2. That is all thats on that web page.

Lets say the URL is: http://192.192.192.192/temps.html

I have a nymea system on the same network and would like to get these values into a generic temp sensor. There are 2 ways i figure this could be done. (Trying to avoid using mqtt)

  1. Have the nymea system run a wget, and head or tail to grab the temp. Then get it into nymea somehow via magic.

  2. Have the magic grab the temp right from the webpage.

If someone could help with the magic i would appreciate it.

–John

Hey John!

I suppose what you want there is a script. You can actually fetch the url directly in the script. Without having tried it, something like this should work:

Timer {
  interval: 10000 //10 seconds
  repeat: true
  onTriggered: {
    var xhr = new XMLHttpRequest;
    xhr.open("GET", "http://192.192.192.192/temps.html");
    xhr.onreadystatechange = function() {
      if (xhr.readyState === XMLHttpRequest.DONE) {
        console.log("Reply from sensors:", xhr.responseText)
      }
    };
    xhr.send();
  }
}

This would fetch the temps.html every 10 seconds and give results in xhr.responseText. I’d suggest to change the web server in a way that it would return a JSON object, for example:

{ temp1: 85, temp2: 79}

Then you can easily parse it in the script with:

var temps = JSON.parse(xhr.responseText)
genericSensor1.temperature = temps["temp1"]
genericSensor2.temperature = temps["temp2"]

Oh, and perhaps you want to use °C instead of °F as nymea:app would translate that to F on its own if the region is set to US. Internally nymea uses SI units.

Hope this helps,
Michael

Michael, thank you for the help! Got it in there but it doesnt seem to produce any output, console or error log. What did i forget:

import QtQuick 2.0
import nymea 1.0

Item {

Timer {
interval: 10000 //10 seconds
repeat: true
onTriggered: {
var xhr = new XMLHttpRequest;
xhr.open(“GET”, “http://192.168.8.199:89/api.html”);
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
console.log(“Reply from sensors:”, xhr.responseText)
var temps = JSON.parse(xhr.responseText);
“Datacenter Temp”.temperature = temps[“temp1”];
“Plenum Temp”.temperature = temps[“temp2”];
}
};
xhr.send();
}
}

}

Oh. Sorry. You’ll need to set the timer to

running: true

Thanks again Michael! Got it that far now, had to put some quotes in the json output on the weberver to get it to parce correctly, so now thats good. Just need to get the generics populating

I have:

    console.log("Reply from sensors:", xhr.responseText)
    var temps = JSON.parse(xhr.responseText);
    "DatacenterTemp".temperature = temps["temp1"];
    "Pl_temp".temperature = temps["temp2"];

So i should use the thing names in the lines:
“DatacenterTemp”.temperature = temps[“temp1”];
“Pl_temp”.temperature = temps[“temp2”];

? Because i tried names and id’s and its not setting the temp.

–John

Ah, you’ll need a ThingState, like this:

ThingState {
  id: myGenericThing
  thingId: "..." // Your thing ID here
  stateName: "temperature"
}

And then you’d set it with myGenericThing.value = temps["temp1"]

More info here: scripting · documentation

Why do i suck at Magic? Im coming to the UK this summer, london a bit but mostly the leeds area, i owe u some beers.

Heres what i got, all seems to work but no updates to my things:

import QtQuick 2.0
import nymea 1.0

Item {

Timer {
interval: 10000 //10 seconds
running: true
repeat: true
onTriggered: {
var xhr = new XMLHttpRequest;
xhr.open(“GET”, “http://192.168.12.102/tmps.html”);
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
console.log(“Reply from sensors:”, xhr.responseText)
var temps = JSON.parse(xhr.responseText);
temp1.value = temps[“temp1”];
temp2.value = temps[“temp2”];

    console.log("Temp1: " + temps["temp1"])
    console.log("Temp2: " + temps["temp2"])


  }
  
};          
        xhr.send();   

}

}

ThingState {
id: temp1
thingId: “3d20b6b4-e536-4b69-8f78-f9e0989043c6” // Your thing ID here
stateName: “input”
}

ThingState {
id: temp2
thingId: “6fad286e-425a-49f2-a4f4-01bb55ebd2c7” // Your thing ID here
stateName: “input”
}

}

Looking at the input state of the generic temperature sensor (here), it has a minvalue 0f 0 and a maxValue of 1. and it defines the sensor range from -20°C to +50°C… So that means you’d need to convert your value to that.

the °F values for -20 and +50°C are: -4 and 122. Mapping that to a 0-1 range would be:

temp1.value = (temps["temp1"] + 4) / 126

A more verbose and easier to change way would be to define a function and use that

function mapValue(value, min, max) {
    return (value - min) / (max - min);
}

...
temp1.value = mapValue(temps["temp1"], -4, 122)

If the -4 to 122 range doesn’t work for you, you can go to the sensor settings and change the range in the settings. Adjust your conversion accordingly.

Admittedly this is a little iffy for your use case, and nowadays nymea could do better but when the generic temperature sensor was written, that was the best the API framework would allow, while still being flexible enough to work for all use cases.

Thanks, got it working perfectly! I converted my web server to send Celisus. Then did the math, it worked but wasnt the right temp. Then i remembered, and this is a thing i was going to ask you why its set that way.

When you go to configure things, and set the min and max of a thing, even though it says “F” since im set in farenheight mode)…you still have to enter those values as C. This got my back on the TPMS project back then too.

For others, here is what the final code was:

import QtQuick 2.0
import nymea 1.0

Item {

Timer {
  interval: 5000 //10 seconds
  running: true
  repeat: true
  onTriggered: {
    var xhr = new XMLHttpRequest;
    xhr.open("GET", "http://192.168.168.111:99/temps.html");
    xhr.onreadystatechange = function() {
      if (xhr.readyState === XMLHttpRequest.DONE) {
        console.log("Reply from sensors:", xhr.responseText)
        var temps = JSON.parse(xhr.responseText);
        

        console.log("Temp1: " + temps["temp1"] + " C")   
                        
        
        temp1.value = mapValue(temps["temp1"], -55, 125)
        console.log (temp1.value)
        
        temp2.value = mapValue(temps["temp2"], -55, 125)
        console.log (temp2.value)
        

      }
      
    };          
            xhr.send();   
  }
  
}


ThingState {
  id: temp1 
  thingId: "3d20b6b4-e536-4b69-8f78-f9e0989043c6" // Your thing ID here
  stateName: "input"
}

ThingState {
  id: temp2
  thingId: "6fad286e-425a-49f2-a4f4-01bb55ebd2c7" // Your thing ID here
  stateName: "input"
}



function mapValue(value, min, max) {

    return (value - min) / (max - min);

}


}

Well, internally nymea works with SI units. The also keeps °C internally all over the place, just translates it to whatever the user wants before displaying. The script engine on the other hand, hooks into the internals of nymea and has no such translation layer in place. So even if you think you’d be changing the min/max in °F, the app actually translates that to °C before sending it to nymea.

(Also, I’ve take the freedom to edit your last post and properly set the code markers for easier reading.)