Python - ruuvitag_sensor package

I would go with RuuviTagSensor.get_data_for_sensors, but would add one extra layer of handling on top of it.

  • Get all found data every 10 sec with RuuviTagSensor.get_data_for_sensors
  • If data is new or changed add it to all_data dictionary with a current timestamp
    • Ignore data that is not changed
  • Send all new data to DB
  • Clear sensors from all_data dict that haven’t got any new data in x seconds/minutes
all_data = {}

while True:
    datas = RuuviTagSensor.get_data_for_sensors([], 10)
    current_time = datetime.now()

    for key, value in datas.items():
        if key in all_data and all_data[key]['data'] == value:
            continue
        all_data[key] = {'data': value, 'timestamp': current_time}

    new_data = {key: value for key, value in all_data.items() if value['timestamp'] is current_time}
    # TODO: insert new_data to DB

    not_found = [key for key, value in all_data.items() if value['timestamp'] < datetime.now() - timedelta(minutes=5)]
    for key in not_found:
        del all_data[key]

I don’t have any RuuviTags with my at the moment, so can’t verify that this actually works, but it is relatively simple, so it should :slight_smile:

Code works, thanks!
However my problem is still that get_data_for_sensors() only returns one dataset for each senor and time interval. In my current setup I have a modified version of the Weatherstation that for sudden sensor value changes is advertising more frequently (few times each second). So my Tags can advertise in the range of 200ms - 10s, where 10s is default state. Should I have a look on get_data_for_sensors() and make a new command that fits my need?

Ok, missed some requirements, so time for the next iteration :slight_smile: Let’s try another simple solution. RuuviTagSensor.get_datas should return all advertised data, so let’s use that and pretty much same handling as previous solution had. Still can’t verify that this works, but if previous one did, maybe this one will also.

all_data = {}
last_clean = datetime.now()


def handle_data(new_data):
    current_time = datetime.now()
    key = new_data[0]
    value = new_data[1]

    if key not in all_data or all_data[key]['data'] != value:
        all_data[key] = {'data': value, 'timestamp': current_time}
        # TODO: Insert new_data to DB etc.

    # Do not check all datas with every handle_data call
    global last_clean
    if last_clean < current_time:
        last_clean = current_time
        not_found = [key for key, value in all_data.items() if value['timestamp'] < current_time - timedelta(minutes=10)]
        for key in not_found:
            # TODO: Notify of lost sensors
            del all_data[key]

RuuviTagSensor.get_datas(handle_data)

Performance wise this is not the best solution as writing to db can be slow, but let’s hope that db writes are fast :slight_smile: Also cleanup is in the same handle_data function, so it is an ugly solution, but maybe for now we can live with that.

I’ve tried this solution before but then I must have screwed up the code (popping the dictionary) making the save-to-db-handle run more or less continuously. Now, with more proper code it works, thanks!
I have the DB on the same machine so for now it seems like writing speed is sufficient. Although I guess I need something to aggregate older data in the DB over time to keep the size down.

Hi,

anyone can advise what i should do to fix this error ?

pi@raspberrypi:~/ruuvitag $ sudo ./ruuvitag-logger.py
Traceback (most recent call last):
File “./ruuvitag-logger.py”, line 6, in
from ruuvitag_sensor.url_decoder import UrlDecoder
ImportError: No module named ‘ruuvitag_sensor.url_decoder’

thanks

I think the module is called decoder and not url_decoder, i.e.:
from ruuvitag_sensor.decoder import UrlDecoder
https://github.com/ttu/ruuvitag-sensor/blob/master/ruuvitag_sensor/decoder.py

thanks. looks working but facing another error when running the script

root@raspberrypi:/home/pi/ruuvitag# ./ruuvitag-logger.py
2017-10-14 00:18:41

Looking for 3: Downstairs (EF:7E:86:D7:3C:6E)
Encoded value: (2, ‘BIQdAMZwS’) not valid
Traceback (most recent call last):
File “/home/pi/ruuvitag-sensor/ruuvitag_sensor/decoder.py”, line 72, in decode_data
decoded = bytearray(base64.b64decode(encoded, ‘-_’))
File “/usr/lib/python3.5/base64.py”, line 81, in b64decode
s = _bytes_from_decode_data(s)
File “/usr/lib/python3.5/base64.py”, line 46, in _bytes_from_decode_data
"string, not %r" % s.class.name) from None
TypeError: argument should be a bytes-like object or ASCII string, not 'tuple’
Data received: None
Traceback (most recent call last):
File “./ruuvitag-logger.py”, line 99, in
for sensor, value in data.items():
AttributeError: ‘NoneType’ object has no attribute ‘items’

Hi,

I think this might be the problem. convert_data function returns a tuple, which has data format type and data

Pass only data value from the tuple to decode function.

If there is still some problem, can you paste the failed part from your source code so it is easier to see where the problem might be. Although usually error message is already enough :slight_smile:

3 Likes

thanks alot. yes. it is working now as per your suggestion.

Hi! I’ve noticed that when my Python code is executed from rc.local (i.e. at startup) the RuuviTagSensor.get_data_for_sensors() is fireing off new processes that are not terminated. I.e. each time RuuviTagSensor.get_data_for_sensors() is called hcitool lescan and hcidump are executed again. This memory leak fills up the RAM… From top I identified the processes and the looked up the pid:s.

pi@raspberry:~ $ ps 2188
PID TTY STAT TIME COMMAND
2188 ? S 0:00 hcitool lescan --duplicates
pi@raspberry:~ $ ps 2231
PID TTY STAT TIME COMMAND
2231 ? S 0:00 sudo -n hcidump --raw

Note: This does not happen when I execute my Python code on the command line using nohup, doesn’t matter if the user is pi or root. Does anyone have any idea why, or has been able to reproduce it? I guess the error lies in:
def stop(hcitool, hcidump):
in ble_communication.py but I have not looked further for now.

Problem solved. Error on my part (having added operand “&” at end of line in rc.local)

… just received my first three brand new RuuviTags!
Great library (!) - everything’s working fine so far except that I am wondering how to check if a certain RuuviTag is present. I tried something like this:

from ruuvitag_sensor.ruuvitag import RuuviTag
    
sensor = RuuviTag('F3:61:D0:6E:2B:9C')
state = sensor.update()

if not state is None:
	print('Temp = {0:0.1f}*C'.format(state["temperature"]))

If the RuuviTag is up and running everything is fine but if the device is switched off (or out of reach) the script does not terminate (seems that there is no timeout).
Sorry for this simple questions - I am pretty sure I have overseen something. I am using Python 3.6.0 on a Raspberry Pi Zero W.

Greetings from Aachen, Germany

Sorry for delay in approving the message, it got held in moderation queue for some reason. Please ping us at Slack if the automoderation gives you any further issues

… meanwhile found a possible solution:

from ruuvitag_sensor.ruuvi import RuuviTagSensor
    
mac = "F3:61:D0:6E:2B:9C"
data = RuuviTagSensor.get_data_for_sensors(mac, 5)

if mac in data:
    print(data[mac])
else:
    print("no data found")

Are there any other approaches?

Sorry for the late reply and thanks for bringing this up. Sometimes it is easy to forget to add some basic functionality when you don’t need those on your own applications :slight_smile:

Unfortunately the package doesn’t provide any simple way to check if Tag is present and both checks that you have implemented are valid.

Maybe we could add these kind of helper functions to the package, so there is no need for everyone to figure these things out on their own. I created a new issue to GitHub: https://github.com/ttu/ruuvitag-sensor/issues/33. You can comment there or to this thread if you have some suggestions for other features.

Package has now an experimental cross-platfom implementation. It uses Bleson BLE module, which is still at alpha stage.

Implementation with Bleson is in branch: bleson-ble-communication

ruuvitag-sensor package must use the development version of Bleson, so module needs to be installed from Bleson’s GitHub repostitory (therefore process-dependency-links is required)

Installation:

$ git clone https://github.com/ttu/ruuvitag-sensor.git
$ cd ruuvitag-sensor
$ git checkout bleson-ble-communication
$ pip install -e . --process-dependency-links

More info on GitHub issues #31 and #18

1 Like

Recently, I have get pi3 B+ model. Configured everything working fine. When I put my ruuvitag inside my freezer, sometime i can detect but most the time I can’t get it. Apparently, I have another pi zero w, configure same thing, but without any issue. I can get sensor data all the time. Anyone experience this?
I have 2 ruuvitag

**I believed it could be the RPi3 B+ antenna limitation. I took the sd card move to pi zero w it work perfectly.

Bonjour les données récupérées de ruuviTag comment peut-on les stocker en csv sur raspberry

please forgive the naive question, but it would be an immense help if someone would advise whether or not it is possible to install this on a Pi that does not have internet access.
Could I point it at, or get the files off of another Pi in my environment that does have the package installed?
any ideas or help with direction at all would be greatly appreciated.
thanks

It would be easiest to setup a SD card with internet-connected Pi and leave the InfluxDB on the Pi. You can then use the created image offline