DS18B20 --- Reading while getting other chores done

Discussion about programs, libraries and tools that work with MicroPython. Mostly these are provided by a third party.
Target audience: All users and developers of MicroPython.
doceave
Posts: 31
Joined: Fri Feb 14, 2020 4:02 pm

DS18B20 --- Reading while getting other chores done

Post by doceave » Mon Feb 17, 2020 1:31 pm

Hi there

I find myself in a situation where this is to expensive, in terms of time, to execute:
import time, ds18x20
ds = ds18x20.DS18X20(ow)
roms = ds.scan()
ds.convert_temp()
time.sleep_ms(750)
for rom in roms:
print(ds.read_temp(rom))
There is only need to check temperature every 2 sec or so, however, during the 750ms above the ESP32 needs to be reading values from an ADC and making decisions based on this every 100ms ---- I.E. The program cannot wait around for 750ms.

Would it be possible to use timer based callbacks to initiate scanning, and another to read values 750ms later? Perhaps an expert would consider the code below and let me know what's wrong with it?
import time, ds18x20
from machine import Timer
ds = ds18x20.DS18X20(ow)

def (scan_ow):
global roms
roms = ds.scan()
ds.convert_temp()
tim.init(period=750, mode=Timer.ONE_SHOT, callback=read_ow)

def (read_ow):
global roms
for rom in roms:
print(ds.read_temp(rom))

tim = Timer(-1)
tim.init(period=1000, mode=Timer.PERIODIC, callback=scan_ow)

I = 0
latest_temp = 0
roms = 0

while True:
# Do other import stuff...
# ...like count to infinity...
pass
pass
pass
pass
pass
time.sleep_ms(1000)
print (I)
I = I + 1
I only expect a stock of DS18B20's to arrive in the next few days. Help in the interim would be greatly appreciated.

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: DS18B20 --- Reading while getting other chores done

Post by Roberthh » Mon Feb 17, 2020 2:35 pm

You can of course start the temperature measurement, do something else and read back the value later. There is no maximum wait time, just a minimum, depending on the chosen resolution.

User avatar
jimmo
Posts: 2754
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: DS18B20 --- Reading while getting other chores done

Post by jimmo » Tue Feb 18, 2020 2:07 am

The simplest way to rethink this is on (say a 50ms) interval:

Code: Select all

n = 0
while True:
  if n == 30:
    n = 0
  if n % 2 == 0:
    # this happens every 100ms
  if n % 15 == 0:
    # this happens every 750ms
    # get result from previous scan
    # start new scan
Some sort of state machine would be useful here, using the current time to detect when things should happen. i.e. busy loop until the next time is up.

But really, what you probably want is asyncio. Create two tasks:

Code: Select all

import asyncio

async def adc_task():
  while True:
    # do adc stuff
    await asyncio.sleep_ms(100)
    
async def ds18x20_task():
  while True:
    # start scan
    await asyncio.sleep_ms(750)
    # finish scan
    
async def main():
  t1 = asyncio.create_task(adc_task())
  t2 = asyncio.create_task(ds18x20_task())
  await t1
  await t2

asyncio.run(main())
(This is (untested, written on my phone, sorry) based the Python 3.8 API, which is supported by "new" uasyncio -- https://github.com/micropython/micropython/pull/5332 -- but could be adapted to the existing version on micropython-lib)

See https://github.com/peterhinch/micropython-async/ and https://github.com/peterhinch/micropyth ... UTORIAL.md

Note: if it's very important that your ADC samples are _exactly_ 100ms apart, then you'll have to do smarter things, but this is a good base to work on -- it's well worth investigating asyncio.

User avatar
tve
Posts: 216
Joined: Wed Jan 01, 2020 10:12 pm
Location: Santa Barbara, CA
Contact:

Re: DS18B20 --- Reading while getting other chores done

Post by tve » Tue Feb 18, 2020 5:18 am

Also consider that 750ms is for a 12-bit reading, which I believe is overkill. I always use 10-bit resolution, which takes much less time and I feel represents about the best accuracy you can get unless you calibrate each individual sensor and pay extremely careful attention to how you transfer heat to the device in your mount...

doceave
Posts: 31
Joined: Fri Feb 14, 2020 4:02 pm

Re: DS18B20 --- Reading while getting other chores done

Post by doceave » Tue Feb 18, 2020 7:52 pm

Jimmo!! :) This uasyncio appears to be the ideal solution albeit way above my level....

I have installed the standard MicroPython v1.12 (2019-12-20) with IDF3

Thus far I have managed to do the following:

> Install the uasyncio library using these instructions --- https://github.com/peterhinch/micropyth ... bare-metal
--- No error on importing of uasyncio so I assume this has been done correctly (4 files copied with corresponding folder structure)

> Copy the adapted script to the ESP32
import uasyncio as asyncio
from time import sleep_ms, ticks_ms

async def adc_task():
while True:
pass
pass
print ("Doing ADC things......")
await asyncio.sleep_ms(100)

async def ds18x20_task():
while True:
print ("Doing temperature things: Starting Scan....")
await asyncio.sleep_ms(750)
print ("Doing temperature things: Reading Temperatures....")

async def main():
t1 = asyncio.create_task(adc_task())
t2 = asyncio.create_task(ds18x20_task())
await t1
await t2

asyncio.run(main())
Sadly it would appear that I have not adapted the code well enough as the following error results on running (on the last line of code):
>>> import fast_temp
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "fast_temp.py", line 23, in <module>
AttributeError: 'module' object has no attribute 'run'
>>>
Would you kindly point out any error that may have crept in?

It looks to me as though we are not properly initiating the asyncio tasks.....

Thanks.

kevinkk525
Posts: 969
Joined: Sat Feb 03, 2018 7:02 pm

Re: DS18B20 --- Reading while getting other chores done

Post by kevinkk525 » Tue Feb 18, 2020 9:36 pm

Code: Select all

import uasyncio as asyncio

async def adc_task():
    while True:
        print ("Doing ADC things......")
        await asyncio.sleep_ms(100)

async def ds18x20_task():
    while True:
        print ("Doing temperature things: Starting Scan....")
        await asyncio.sleep_ms(750)
        print ("Doing temperature things: Reading Temperatures....")

loop=asyncio.get_event_loop()
t1 = loop.create_task(adc_task())
t2 = loop.create_task(ds18x20_task())

loop.run_forever()
Jimmo's code would only work with the new uasyncio version which isn't implemented yet.
Kevin Köck
Micropython Smarthome Firmware (with Home-Assistant integration): https://github.com/kevinkk525/pysmartnode

doceave
Posts: 31
Joined: Fri Feb 14, 2020 4:02 pm

Re: DS18B20 --- Reading while getting other chores done

Post by doceave » Tue Feb 18, 2020 9:38 pm

Thanks so much Kev.... Almost midnight here in South Africa ---- this is first on my list of things to test tomorrow! :)

A super simple tutorial on implementation of this awesome feature is probably needed somewhere.

kevinkk525
Posts: 969
Joined: Sat Feb 03, 2018 7:02 pm

Re: DS18B20 --- Reading while getting other chores done

Post by kevinkk525 » Tue Feb 18, 2020 9:47 pm

Kevin Köck
Micropython Smarthome Firmware (with Home-Assistant integration): https://github.com/kevinkk525/pysmartnode

doceave
Posts: 31
Joined: Fri Feb 14, 2020 4:02 pm

Re: DS18B20 --- Reading while getting other chores done

Post by doceave » Wed Feb 19, 2020 5:42 pm

Hi there KevinKK525 ---- I am so sorry to bother with NOOB requests.

Your modification of Jimmo's code is below:

Code: Select all

import uasyncio as asyncio

async def adc_task():
    while True:
        print ("Doing ADC things......")
        await asyncio.sleep_ms(100)

async def ds18x20_task():
    while True:
        print ("Doing temperature things: Starting Scan....")
        await asyncio.sleep_ms(750)
        print ("Doing temperature things: Reading Temperatures....")

loop = asyncio.get_event_loop()
t1 = loop.create_task(adc_task())
t2 = loop.create_task(ds18x20_task())

loop.run_forever()
I have confirmed that all uasync files have been copied in the correct places on the ESP32 file system.
I am running standard MicroPython v1.12 (2019-12-20) firmware.
Uasyncio files sourced from https://github.com/micropython/micropython-lib as per PeterHinch' instructions in the tutorial you linked.
Sadly the following error results:
>>> import uasync.py
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "uasync.py", line 14, in <module>
AttributeError: 'module' object has no attribute 'get_event_loop'
>>>
Whilst not ideal, if I am able, with your help, to get just this basic example working, I am sure that I can figure the rest out myself. This example will serve as an excellent template for other tasks that would do well with a few 'await' points.

Please let me know where I can scout next for solutions to this error above....
> uPython-asyncio version incompatibility?
> Error in the example code provided?

Thanks in advance.
Last edited by doceave on Wed Feb 19, 2020 6:27 pm, edited 1 time in total.

kevinkk525
Posts: 969
Joined: Sat Feb 03, 2018 7:02 pm

Re: DS18B20 --- Reading while getting other chores done

Post by kevinkk525 » Wed Feb 19, 2020 6:25 pm

If you installed uasyncio correctly then this should not happen.

Tell me the output of:

Code: Select all

>>> import uasyncio as asyncio
>>> dir(asyncio)
Kevin Köck
Micropython Smarthome Firmware (with Home-Assistant integration): https://github.com/kevinkk525/pysmartnode

Post Reply