1

I'm a JS dev trying to learn a bit of Python while working on a Raspberry-Pi3 project that reads data from a Bluetooth temperature sensor.

I need to write the data to my file.txt every 10 seconds, how could I do that please? I found similar topic here (Run certain code every n seconds ), but I don't know how to make it work in my current scenario.

#!/usr/bin/env python3

import argparse
import re
import logging
import sys
import time

from btlewrap import available_backends, BluepyBackend, GatttoolBackend, PygattBackend
from mitemp_bt.mitemp_bt_poller import MiTempBtPoller, \
    MI_TEMPERATURE, MI_HUMIDITY, MI_BATTERY

def valid_mitemp_mac(mac, pat=re.compile(r"4C:65:A8:[0-9A-F]{2}:[0-9A-F]{2}:[0-9A-F]{2}")):
    """Check for valid mac adresses."""
    if not pat.match(mac.upper()):
        raise argparse.ArgumentTypeError('The MAC address "{}" seems to be in the wrong format'.format(mac))
    return mac

def poll(args):
    """Poll data from the sensor."""
    backend = _get_backend(args)
    poller = MiTempBtPoller(args.mac, backend)
    line1 = "Temperature: {}".format(poller.parameter_value(MI_TEMPERATURE))
    line2 = "Humidity: {}".format(poller.parameter_value(MI_HUMIDITY))
    print("Getting data from Mi Temperature and Humidity Sensor")
    print("FW: {}".format(poller.firmware_version()))
    print("Name: {}".format(poller.name()))
    print("Battery: {}".format(poller.parameter_value(MI_BATTERY)))
    print(line1)
    print(line2)
    f = open('file.txt', 'w')
    f.write("%s \n %s \n" % (line1, line2))
    f.close()

def _get_backend(args):
    """Extract the backend class from the command line arguments."""
    if args.backend == 'gatttool':
        backend = GatttoolBackend
    elif args.backend == 'bluepy':
        backend = BluepyBackend
    elif args.backend == 'pygatt':
        backend = PygattBackend
    else:
        raise Exception('unknown backend: {}'.format(args.backend))
    return backend


def list_backends(_):
    """List all available backends."""
    backends = [b.__name__ for b in available_backends()]
    print('\n'.join(backends))

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--backend', choices=['gatttool', 'bluepy', 'pygatt'], default='gatttool')
    parser.add_argument('-v', '--verbose', action='store_const', const=True)
    subparsers = parser.add_subparsers(help='sub-command help', )

    parser_poll = subparsers.add_parser('poll', help='poll data from a sensor')
    parser_poll.add_argument('mac', type=valid_mitemp_mac)
    parser_poll.set_defaults(func=poll)

    parser_scan = subparsers.add_parser('backends', help='list the available backends')
    parser_scan.set_defaults(func=list_backends)

    args = parser.parse_args()
    if args.verbose:
        logging.basicConfig(level=logging.DEBUG)

    if not hasattr(args, "func"):
        parser.print_help()
        sys.exit(0)

    args.func(args)


if __name__ == '__main__':
    main()
kosist
  • 2,868
  • 2
  • 17
  • 30
Cristian Muscalu
  • 9,007
  • 12
  • 44
  • 76

2 Answers2

3

You can use the time module to pause the program for 10 seconds on each iteration;

from time import sleep

def func(n):
    print(n+1)

for i in range(5):
    func(i)
    sleep(10)

>1
>2
>3
>4
>5

# (every 10 seconds)

However this will block the rest of the program running, although a simple multi-threading script to call the writing function would suffice.

And in relation to the code you are using, insert the sleep call within the poll function and wrap what you have there. If you want to loop the program 10 times then;

def poll(args):
    """Poll data from the sensor."""
    for _ in range(10):
        # code things
        f = open('file.txt', 'a') # << Use append here or you will keep overwriting file contents
        f.write('hello')
        f.close()
        sleep(10)

Or if you want it to run forever until you KeyboardInterrupt or exit somehow:

def poll(args):
    """Poll data from the sensor."""
    while True:
        # code things
        f = open('file.txt', 'a') # << Use append here or you will keep overwriting file contents
        f.write('hello')
        f.close()
        sleep(10)
Nordle
  • 2,915
  • 3
  • 16
  • 34
  • I added this before/after the poll function, and it seems to ignore the rest of my code. It's only doing print1,2,3.. How can i use it to also make use of the `poll` function? – Cristian Muscalu Mar 19 '19 at 07:00
  • @PatrickArtner yes, but for the moment i'm fine with that. I will just use that file and pick-up from there using Node (which i know better for now). I couldn't find any node package that would read the sensor, so i'm forced to use python. – Cristian Muscalu Mar 19 '19 at 07:09
  • I stripped the code out and just leaving the 'example' – Nordle Mar 19 '19 at 07:12
  • I will use my node server to read whatever is in that file at a particular time and that will be my data. – Cristian Muscalu Mar 19 '19 at 07:12
  • Matt B. i will use with you solution for now, since it's easier to use and closer to my level. Thanks! – Cristian Muscalu Mar 19 '19 at 07:24
2
  1. you need some kind of loop that polls your sensor - I do not see one glancing over your code. You got while and for loops in JS as well - look them up in http://docs.python.org/3/tutorial if you are unsure about the syntax.

  2. store the time you wrote to a variable , sleep a bit poll the next value, check if 10s passed, write if, else not. (or simply sleep 10s between polls if you do not want intermediate values printed

Readup about loops:


import time

def poll():
    return time.time(), 42

last_write = None    # when did we record to file last?

# loop for as long as you want - while True would loop endlessly
for _ in range(7):
    t,c = poll()     # call poll() to get time and temperature from mocked data reader

    # check if enough time has passed
    if last_write is None or (t-last_write) > 2:  # check if new reading needed
        with open("t.txt","a") as f:
            f.write(f"{t}    {c}\n")
        last_write=t
        print("in file ", t,c)            
    else:
        print("just output ", t,c)
    time.sleep(0.7)                               # sleep some

Output:

in file  1552978725.5224085 42                # ...25.5
just output  1552978726.2232893 42            # ...26.2  - not 2s passed 
just output  1552978726.9241226 42            # ...26.9  - not 2s passed
in file  1552978727.6249442 42                # ...27.6  - 2.1s passed 
just output  1552978728.3259027 42            # ...28.3  - not 2s passed
just output  1552978729.0267787 42            # ...29.0  - not 2s passed 
in file  1552978729.7275977 42                # ...29.7  - 2.1s passed

More remarks:

  • use with open(filename,mode) as f: and scope the file opeations below it - it will autoclose your file after scope and handle exceptions by closing the filehandle as well.

  • Using mode "w" will truncate the file before writing to it - you might want to use append instead: reading and writing files

Patrick Artner
  • 50,409
  • 9
  • 43
  • 69