0

Basic Help! Need to understand read() and write()
Moderators: adafruit_support_bill, adafruit

Forum rules
If you're posting code, please make sure your code does not include your Adafruit IO Active Key or WiFi network credentials.
Please be positive and constructive with your questions and comments.

Basic Help! Need to understand read() and write()

by Rcayot on Thu Mar 18, 2021 9:09 am

I know this isn;t an fundamental AIO request, but I am having trouble finding teh resource that can help me help myself.

I am dealing with an AIO project. My bme280 sensor on an nRF52840 communicating with a Pi Zero W via BLE, and the Pi sending data to AIO via wifi.

Here is my problem. I am sending and recieving data via UART service in BLE UART. The problems are that I cannot find the resources to help me understand the formatting type arguments that go with those functions. for example the line:
uart_service.write(request_temperature.encode("utf-8"))

I cannot find for the life of me the Python or Circuitpython API information on whatever the '.encode("utf-8")' part means. I mean I do, I looked up what utf-8 means.

Here is another. I understand that str(result) means the information inside 'result' is sent as a string. But why is it not using 'encode("utf-8)"? Also why are they adding the lineuart_service.write(b'\n')? What does (b, '\n') mean? I really do not need to know those specific answers, but I need a reference to somewhere that discusses or tutorial that covers these things. Believe me I have tried looking in Python and here at Adafruit.

Anyway, please help me find out how I can improve my understanding of this topic. I am still having trouble with my project (covered in several of my latest posts. And while it 'works' it fails occasionally due to recieving an 'empty' string. And while I can catch that, what also happens is that the next round of .read() ends up reading the data that was missing from the first read! I am tryinjg to understand how I could test for the presence of a string, orsomething to help. What happens is tha tdata say from temperature, ends up in humidity data or humidity for pressure etc.

uart.write(str(result))
uart_service.write(b'\n')




Code: Select all | TOGGLE FULL SIZE
def get_and_send_temperature():
    request_temperature = "bme280.temperature"
    uart_service.write(request_temperature.encode("utf-8"))
    # uart_service.write(b'\n')
    time.sleep(20)
    temperature = uart_service.readline().decode("utf-8")
    data = str(temperature)
    if len(data) > 0:
        print(data, 'recieved')
        data = (1.8)*float(data) + 32.0
        data = round(data, 2)
        time.sleep(1)
        aio.send_data(temperature_feed.key, str(data))
    else:
        print('empty string recieved')
        return
    print(data, 'sent')

Rcayot
 
Posts: 148
Joined: Sat Feb 08, 2020 6:48 pm

Re: Basic Help! Need to understand read() and write()

by brubell on Fri Mar 19, 2021 10:07 am

I cannot find for the life of me the Python or Circuitpython API information on whatever the '.encode("utf-8")' part means. I mean I do, I looked up what utf-8 means.


The API expects a UTF-8 encoded string. So, the `.encode(format)` call takes the temperature (as a string) and then writes it over the UART as a UTF-8-formatted string.


Here is another. I understand that str(result) means the information inside 'result' is sent as a strin

It does not - str(result) converts (formally called casting) the value of result to a string. If result was an integer, calling str(result) would make it a string type instead. You can check this in the Python REPL by typing type(your_variable) and it'll list it, or print that call out to see which type of variable you're accessing.

Also why are they adding the lineuart_service.write(b'\n')? What does (b, '\n') mean?

the b' indicates bytes. The \n indicates a new line character, same as you hitting the ENTER key on your keyboard.

brubell
 
Posts: 1381
Joined: Fri Jul 17, 2015 10:33 pm

Re: Basic Help! Need to understand read() and write()

by Rcayot on Fri Mar 19, 2021 11:11 am

Brubel,
Thaks for the help. I have mostly guessed the ansewers you gave.

I guess I can summarize my issue as follows: How can I clear the UART buffer? I have used the 'evaluate' example to send 'bme280.temperature' to it and after read, it executes an 'eval()' and writes the result back to the RPi.

Occasionally, I get an empty string back. I bypass this with an if len() >0 and else just return. What this inevitably does is eventually actually fill the uart buffer with the requested data.

Now either I can increase the time.sleep(20) to longer and hope before then it gets read correctly. I send a uart.write(str(result)) and then uart_service.write(b'\n') so there is an end of line being sent. Now, I read somewhere that the python 'readline()' command reads until an end of line is read. Is that not so? I would like to know what other python IO type arguments I can add. It appears to me that the UARTService from BLERadio doe snot support any other arguments except the 'payload'(?). I have tried to utilize some things like 'timeout=x)' to increase the read time. Wha tI also understand is that read() (and readline()?) are blocking, but that does not appear to be the case. When I use a print whatever comes across that is 'empty' There is a line return and no characters.

Anyway, two questions, is this just a simple wait longer? Or, is it something I need to handle as an error or something and try to either clear the buffer, or something you can suggest?

Here is code for the RPi:

Code: Select all | TOGGLE FULL SIZE
# pibleuart_ble280
# Connect to an "eval()" service over BLE UART.
# have nRF52840 evaluate temperature, humidity and pressure and return them to RPI bia BLE.
# Rpi will send data to aio via wifi
# Roger Ayotte March 5, 2021
# based on the eval example

# Connect to an "eval()" service over BLE UART.
import time
from adafruit_ble import BLERadio
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
from adafruit_ble.services.nordic import UARTService

ble = BLERadio()
uart_connection = None
sensor_read_delay = 300

from Adafruit_IO import Client, Feed, Data, RequestError
import datetime

# Set to your Adafruit IO key.
# Remember, your key is a secret,
# so make sure not to publish it when you publish this code!
ADAFRUIT_IO_KEY = 'aio_Fzve6425emwZSbMDz9nTeAvjI1dj'

# Set to your Adafruit IO username.
# (go to https://accounts.adafruit.com to find your username).
ADAFRUIT_IO_USERNAME = 'Rcayot'

# Create an instance of the REST client.
aio = Client(ADAFRUIT_IO_USERNAME, ADAFRUIT_IO_KEY)

# Set up Adafruit IO Feeds.
temperature_feed = aio.feeds('temperature')
humidity_feed = aio.feeds('humidity')
pressure_feed = aio.feeds('pressure')

def get_and_send_temperature():
    request_temperature = "bme280.temperature"
    uart_service.write(request_temperature.encode("utf-8"))
    # uart_service.write(b'\n')
    time.sleep(20)
    temperature = uart_service.readline().decode("utf-8")
    data = str(temperature)
    if len(data) > 0:
        print(data, 'recieved')
        data = (1.8)*float(data) + 32.0
        data = round(data, 2)
        time.sleep(1)
        aio.send_data(temperature_feed.key, str(data))
    else:
        print('empty string recieved')
        temperature = uart_service.readline().decode("utf-8")
        return
    print(data, 'sent')

def get_and_send_humidity():
    request_humidity = "bme280.humidity"
    uart_service.write(request_humidity.encode("utf-8"))
    #uart_service.write(b'\n')
    time.sleep(20)
    humidity = uart_service.readline().decode("utf-8")
    data = str(humidity)
    if len(data) > 0:
        print(data, 'recieved')
        time.sleep(1)
        aio.send_data(humidity_feed.key, str(data))
    else:
        print('empty string recieved')
        return
    print(data, 'sent')

def get_and_send_pressure():
    request_pressure = "bme280.pressure"
    uart_service.write(request_pressure.encode("utf-8"))
    #uart_service.write(b'\n')
    time.sleep(20)
    pressure = uart_service.readline().decode("utf-8")
    data = str(pressure)
    if len(data) > 0:
        print(data, 'recieved')
        time.sleep(1)
        aio.send_data(pressure_feed.key, str(data))
    else:
        print('empty string recieved')
        return
    print(data, 'sent')

while True:
    if not uart_connection:
        print("Trying to connect...")
        for adv in ble.start_scan(ProvideServicesAdvertisement):
            if UARTService in adv.services:
                uart_connection = ble.connect(adv)
                print("Connected")
                break
        ble.stop_scan()

    if uart_connection and uart_connection.connected:
        uart_service = uart_connection[UARTService]
        while uart_connection.connected:
            print('temperature requested')
            get_and_send_temperature()
            time.sleep(15)
            print('humidity requested')
            get_and_send_humidity()
            time.sleep(15)
            print('pressure requested')
            get_and_send_pressure()
            time.sleep(600)


here is the code for the nRF52840:

Code: Select all | TOGGLE FULL SIZE
# Provide an "eval()" service over BLE UART.

from adafruit_ble import BLERadio
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
from adafruit_ble.services.nordic import UARTService
import time
import board
import busio
import adafruit_bme280

ble = BLERadio()
uart = UARTService()
advertisement = ProvideServicesAdvertisement(uart)

# Create library object using our Bus I2C port
i2c = busio.I2C(board.SCL, board.SDA)
bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c)


while True:
    ble.start_advertising(advertisement)
    print("Waiting to connect")
    while not ble.connected:
        pass
    print("Connected")
    while ble.connected:
        s = uart.readline()
        if s:
            try:
                result = (eval(s))
                print(result, 'received')
            except Exception as e:
                result = repr(e)
                print(result, 'e')
            uart.write(str(result))
            uart_service.write(b'\n')
            print(result, 'sent')

Rcayot
 
Posts: 148
Joined: Sat Feb 08, 2020 6:48 pm

Re: Basic Help! Need to understand read() and write()

by brubell on Wed Mar 24, 2021 10:47 am

I guess I can summarize my issue as follows: How can I clear the UART buffer? I have used the 'evaluate' example to send 'bme280.temperature' to it and after read, it executes an 'eval()' and writes the result back to the RPi.

https://circuitpython.readthedocs.io/en ... put_buffer

brubell
 
Posts: 1381
Joined: Fri Jul 17, 2015 10:33 pm

Re: Basic Help! Need to understand read() and write()

by Rcayot on Wed Mar 24, 2021 3:43 pm

Brubell,

Thanks. I have reviewed that information. The adafruit ble uart service, however, does not seem to be able to use some of these functions. For example, I tried to set a "timeout" but that returned an error. If I could use sizeof, or some of these others, it would be easier.

What is happening is that thr readline() is empty, I then test for len() of the output. If it is >0 then proceed otherwise, return. This is because I can skip a data point or so. What often happens, however, is that by the time the next read is supposed to happen, The buffer contains the previous values, and the new data are appended to those. I got rid of that problem (mostly) by first reading the buffer into trash, then calling for new sensor data. This works much better, but still has about one or two failures per day.

Perhaps I have not read the API info closely enough.

Does the adafruit BLE Uart service support these BLEIO uart functions?

Rcayot
 
Posts: 148
Joined: Sat Feb 08, 2020 6:48 pm

Re: Basic Help! Need to understand read() and write()

by Rcayot on Thu Mar 25, 2021 11:32 am

Brubell,

Okay, I used:

uart_service.reset_input_buffer()

at the beginning of each call.

I had a uart_service.read(.....) there but did not always clear the buffer. Perhaps more than one reset is required.

Anyway, that particular helpful item is what I was looking for.

Roger Ayotte

Rcayot
 
Posts: 148
Joined: Sat Feb 08, 2020 6:48 pm

Please be positive and constructive with your questions and comments.