Official Ruuvi App: Weather Station

It’s a bit tricky because the name info you see on your phone (HTML page metadata) comes from a web server, not from the RuuviTag. Also, the web server doesn’t know which Tag the exact address came from because those addresses doesn’t include any unique IDs (because of Eddystone-URL space limit).

@otso Or what do you think? Do we have any space left to send for example last two hex numbers of the MAC addresses with each advertisements?

Thanks Lauri.

There needs to be an answer because IMHO the usefulness of BLE sensor tags generally is seriously denigrated if there is no way of telling which individual tag is being read without a separate cross reference system.

We do have 6 bits of data available in the URL, we could put last bits of MAC address and hope that there would not be collisions. We could also make those 6 bits user configurable in the future, so they could assign a new ID in case of a collision.

Right now the idea would be to use those bits for battery voltage, but the battery voltage could be sent in a separate Eddystone TLM package or be read on connection.

Can I ask how the commercial suppliers of tags handle the issue?

Clearly when they sell generic tags the buyer demands his own name returned as the tag identity and that must be programmable.

Just a thought.

Generally the tags come with preprogrammed UUIDs. For example we could make a batch of eddystone tags with namespace UUID client has requested and a random instance ID.

It would also be possible to configure the namespace and instance ID over the air on Eddystone application.
You could create an smartphone app which would continuously scan for Eddystone beacon in configuration mode with name prefix “Ruuvi”. Once beacon would be detected, app would program your namespace and running counter to instance.

Hi I ’ ve managed to decode RuuviTag readings via PhysicalWeb node avaialable . the flow below contains upload to google.docs and visualsiation on node-red dasboard:
[{“id”:“7543a7b7.449e58”,“type”:“PhysicalWeb in”,“z”:“b773c68.2f29c38”,“name”:"",“topic”:"",“duplicates”:true,“x”:98.83332824707031,“y”:47,“wires”:[[“a419f065.47f74”]]},{“id”:“e907ae2c.aca54”,“type”:“debug”,“z”:“b773c68.2f29c38”,“name”:"",“active”:true,“console”:“false”,“complete”:“true”,“x”:806.8332824707031,“y”:376.99998474121094,“wires”:[]},{“id”:“b53412c0.4fbcb”,“type”:“base64”,“z”:“b773c68.2f29c38”,“name”:"",“x”:624.8333129882812,“y”:44.33331298828125,“wires”:[[“61f8ea0.8837918”]]},{“id”:“8579b9e0.db4708”,“type”:“rbe”,“z”:“b773c68.2f29c38”,“name”:"",“func”:“rbe”,“gap”:"",“start”:"",“inout”:“out”,“x”:454.83326721191406,“y”:45,“wires”:[[“b53412c0.4fbcb”]]},{“id”:“a419f065.47f74”,“type”:“function”,“z”:“b773c68.2f29c38”,“name”:“url extract”,“func”:"\nvar lastFive = msg.payload.url.substr(msg.payload.url.length - 8)\nvar newMsg = { payload: lastFive };\nreturn newMsg;",“outputs”:1,“noerr”:0,“x”:290.8332977294922,“y”:45.66668701171875,“wires”:[[“8579b9e0.db4708”]]},{“id”:“61f8ea0.8837918”,“type”:“function”,“z”:“b773c68.2f29c38”,“name”:“decode”,“func”:" var decoded64=msg.payload;\n //node.log(decoded64)\n var humidity = decoded64[1] * 0.5;\n var uTemp = (((decoded64[2] & 127) << 8) | decoded64[3]);\n var tempSign = (decoded64[2] >> 7) & 1;\n var temp = tempSign === 0 ? uTemp/256.0 : -1 * uTemp/256.0;\n var tempF = temp * 1.8 + 32;\n var air_pressure = ((decoded64[4] << 8) + decoded64[5]) + 50000;\n var res={}; \n res.Temp=temp\n res.Humidity=humidity;\n res.Pressure=air_pressure/100;\n //node.log( res)\n var newMsg={ payload: res };\nreturn newMsg;",“outputs”:1,“noerr”:0,“x”:612.8333282470703,“y”:169.00003051757812,“wires”:[[“d9bb357f.34a728”,“5c86ba88.a3f484”,“291bb3a6.38721c”,“5e89fce2.adc8a4”,“e907ae2c.aca54”]]},{“id”:“d9bb357f.34a728”,“type”:“http request”,“z”:“b773c68.2f29c38”,“name”:"",“method”:“GET”,“ret”:“txt”,“url”:“https://docs.google.com/forms/d/e/1FAIpQLSe5y3kieN8awamZH8mddJW8_9TkwCxi_mh38JfxTX6bLN3mWw/formResponse?entry.2129173735={{payload.Temp}}&entry.1724609919={{payload.Humidity}}&entry.392458147={{payload.Pressure}}”,“tls”:"",“x”:848.8332977294922,“y”:103.66665649414062,“wires”:[[]]},{“id”:“37d04bf0.89a474”,“type”:“ui_gauge”,“z”:“b773c68.2f29c38”,“name”:“temp”,“group”:“dcdcb16a.e1794”,“order”:1,“width”:0,“height”:0,“gtype”:“gage”,“title”:“Gauge”,“label”:“units”,“format”:"{{value | number :0 }}C",“min”:"-20",“max”:“50”,“colors”:["#00b500","#e6e600","#ca3838"],“x”:1032.8333587646484,“y”:29.6666259765625,“wires”:[]},{“id”:“5c86ba88.a3f484”,“type”:“function”,“z”:“b773c68.2f29c38”,“name”:“Temp gauge”,“func”:“return {payload:msg.payload.Temp}”,“outputs”:1,“noerr”:0,“x”:854.8332977294922,“y”:29.66668701171875,“wires”:[[“37d04bf0.89a474”]]},{“id”:“5e89fce2.adc8a4”,“type”:“function”,“z”:“b773c68.2f29c38”,“name”:“Humidity Gauge”,“func”:“return {payload:msg.payload.Humidity}”,“outputs”:1,“noerr”:0,“x”:854.8332977294922,“y”:169.66668701171875,“wires”:[[“f2748697.ed1178”]]},{“id”:“291bb3a6.38721c”,“type”:“function”,“z”:“b773c68.2f29c38”,“name”:“Pressure Gauge”,“func”:“return {payload:msg.payload.Pressure}”,“outputs”:1,“noerr”:0,“x”:846.8333282470703,“y”:259.6666717529297,“wires”:[[“8c5e9d0c.1cd61”]]},{“id”:“8c5e9d0c.1cd61”,“type”:“ui_gauge”,“z”:“b773c68.2f29c38”,“name”:"",“group”:“b99d7751.f24e88”,“order”:1,“width”:0,“height”:0,“gtype”:“gage”,“title”:“Pressure”,“label”:“units”,“format”:"{{value}}",“min”:“800”,“max”:“1050”,“colors”:["#00b500","#e6e600","#ca3838"],“x”:1032.8333587646484,“y”:260.3332824707031,“wires”:[]},{“id”:“f2748697.ed1178”,“type”:“ui_gauge”,“z”:“b773c68.2f29c38”,“name”:"",“group”:“2bcb7a68.a61ad6”,“order”:0,“width”:0,“height”:0,“gtype”:“gage”,“title”:“Humidity”,“label”:“units”,“format”:"{{value}}%",“min”:0,“max”:“120”,“colors”:["#00b500","#e6e600","#ca3838"],“x”:1034.8333587646484,“y”:170.33331298828125,“wires”:[]},{“id”:“dcdcb16a.e1794”,“type”:“ui_group”,“z”:"",“name”:“Group”,“tab”:“3ec967de.6c75c8”,“order”:null,“disp”:false,“width”:“6”},{“id”:“b99d7751.f24e88”,“type”:“ui_group”,“name”:“Group”,“tab”:“3ec967de.6c75c8”,“order”:null,“disp”:true,“width”:6},{“id”:“2bcb7a68.a61ad6”,“type”:“ui_group”,“name”:“Group”,“tab”:“3ec967de.6c75c8”,“order”:null,“disp”:true,“width”:6},{“id”:“3ec967de.6c75c8”,“type”:“ui_tab”,“z”:"",“name”:“Tab 1”,“icon”:“dashboard”,“order”:1}]

The second option sounds good, Otso.

At the moment I am having to manually log the first part of the URL in a note and refer to it to check which tag I am looking at.

With only three tags its cumbersome, with twenty in range, it will simply not work and I think many sensor monitoring applications will suffer the same issues.

I’m not an expert in the Eddystone packet format but I agree, wouldn’t using the Eddystone-TML package solve this problem? Using Eddystone-UID to identify the unit and Eddystone-TLM to send sensor data. It would also be good in the future to have the option to use the Eddystone-EID frame type if one needs the information to encrypted.

You are correct, adding Eddystone-TLM, Eddystone-UID and Eddystone-EID would cover a lot of use-cases.

There is a matter of power optimization: if we broadcast 4 packets instead of one in the same interval the power consumption almost quadruples. Therefore user should be able to configure which packets they actually need. Easiest way to approach this would be to modify the Eddystone firmware to detect base url “ruu.vi/#” and fill in the sensor data when applicable.

Even with the Eddystone features the original issue of detecting “which beacon has sent this URL” would not be well resolved, though, as the website is unaware of every other packet in the air. In longer term, having web-bluetooth application read user set name from tags would be ideal.

I cannot promise an exact schedule for a proper web-bluetooth demo for reading sensors, but right now “April - May” looks pretty realistic.

I have some error in decode function. Why?

The line 4 should have a bit-shift, possibly

var uTemp = (((decoded64[2] & 127) << 8) | decoded64[3]);

Edit: something more is done on the line below, it would be helpful if the entire code would be shown.
That line might be for taking the sign bit, in which case it should be

var uTemp = (((decoded64[2] & 127) >> 7) &1;

var decoded64=msg.payload;
//node.log(decoded64)
var humidity = decoded64[1] * 0.5;
var uTemp = ((decoded64[2] & 127) >> 7) & 1;
var temp = tempSign === 0 ? uTemp/256.0 : -1 * uTemp/256.0;
var tempF = temp * 1.8 + 32;
var air_pressure = ((decoded64[4] << 8) + decoded64[5]) + 50000;
var res={};
res.Temp=temp;
res.Humidity=humidity;
res.Pressure=air_pressure/100;
//node.log( res)
var newMsg={ payload: res };
return newMsg;

It’s a little bit strange for me. I don’t understand lack of var tempSign, and the temp, humidity and pressure format. Temp has decimal place, or it is only integer? THX for help! Nem

Please refer to specification for details (and let me know if something needs clarification!)

I think the code has a bug in temperature sign handling, the way ruu.vi site does it is:

var uTemp = (((decoded[3] & 127) << 8) | decoded[2]);
var tempSign = (decoded[3] >> 7) & 1;
var temp = tempSign === 0 ? uTemp/256.0 : -1 * uTemp/256.0;
var tempF = temp * 1.8 + 32;

var decoded64=msg.payload;
//node.log(decoded64)
var humidity = decoded64[1] * 0.5;
var uTemp = (((decoded64[2] & 127) << 8) | decoded64[3]);
var tempSign = (decoded64[2] >> 7) & 1;
var temp = tempSign === 0 ? uTemp/256.0 : -1 * uTemp/256.0;
var tempF = temp * 1.8 + 32;
var air_pressure = ((decoded64[4] << 8) + decoded64[5]) + 50000;
var res={};
res.Temp=temp;
res.Humidity=humidity;
res.Pressure=air_pressure/100;
//node.log( res)
var newMsg={ payload: res };
return newMsg;

This is the working version. I work now fractional part of temperature reading.

Please note that the base weather station does not send fractions

Ok, thx! I hope the future versions can send fraction values, too!

Another use case that may be relevant to other users.

An app to decode the sensor data with no Wifi connection.

Which language is this please?

Node-red function, javascript. From message 45.

Temp measurements off by 10-15C in sauna. Is there a way to calibrate the sensors?