Help converting bytes to int [resolved]

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
Post Reply
jpj
Posts: 60
Joined: Sat Dec 10, 2016 3:07 pm

Help converting bytes to int [resolved]

Post by jpj » Mon Jan 17, 2022 8:15 pm

I'm developing a project using micropython on a Raspberry Pi Pico with an RTC clock, temp sensor, and displaying on a 1602 LCD. It's working thanks libraries and tutorials written and shared by others like David Hyland. Thank you!

I'm stuck trying to convert then compare the bytes returned from the RTC with integers. For example I would like to code:

Code: Select all

if (minute == 30) and (second == 0):
    do_something()
I can't figure out how to cast or convert the bytes returned from the RTC, so right now I have a simple counter in an "if" statement. My code and some photos follow.

Thanks for any help.
Jake

Code: Select all

from lcd_api import LcdApi
from i2c_lcd import I2cLcd
from machine import I2C
from machine import Pin
from tmp102 import Tmp102
import time

# 1602 LCD 0x27
I2C_ADDR     = 0x27
I2C_NUM_ROWS = 2
I2C_NUM_COLS = 16

# DS3231 RTC 0x68
RTC_ADDR = 0x68
RTC_REGISTER = 0x00

i2c = I2C(0, sda=machine.Pin(0), scl=machine.Pin(1), freq=400000)

lcd = I2cLcd(i2c, I2C_ADDR, I2C_NUM_ROWS, I2C_NUM_COLS)

def ds3231ReadTime():
	return i2c.readfrom_mem(int(RTC_ADDR),int(RTC_REGISTER),7);

# tmp102 temperature sensor
TMP102 = Tmp102(i2c, 0x48)
tempC=0
tempF=0


if __name__ == "__main__":
    lcd.move_to(0,0)
    lcd.putstr("* Raspberry Pi *")
    lcd.move_to(0,1)
    lcd.putstr("*     PICO     *")
    time.sleep(2)
    lcd.clear()
    count = 0
    while True:
        t = ds3231ReadTime()
        second = t[0]&0x7F  #sec
        minute = t[1]&0x7F  #min
        hour   = t[2]&0x3F  #hour
        week   = t[3]&0x07  #week
        day    = t[4]&0x3F  #day
        month  = t[5]&0x1F  #month
        year   = t[6]&0x3F  #year

        lcd.move_to(0,0)
        lcd.putstr("20%x-%02x-%02x %02x:%02x" % (year,month,day,hour,minute))
        lcd.move_to(0,1)
        lcd.putstr("* Raspberry Pi *")

        print("20%x-%02x-%02x %02x:%02x:%02x" % (year,month,day,hour,minute,second))

        time.sleep(1)
        if count == 14:
            tempC = TMP102.temperature
            tempF = (tempC * 9/5 + 32)
            print("tempC {0:.1f} tempF {0:.1f}".format(tempC, tempF))
            lcd.clear()
            lcd.move_to(0,0)
            lcd.putstr("Temp C {0:.1f}".format(tempC))
            lcd.move_to(0,1)
            lcd.putstr("Temp F {0:.1f}".format(tempF))
            time.sleep(3)
            lcd.clear()
            count = 0
        
        count += 1
 
Attachments
IMG_0325.jpeg
IMG_0325.jpeg (114.92 KiB) Viewed 9291 times
IMG_0324.jpeg
IMG_0324.jpeg (200.44 KiB) Viewed 9291 times
Last edited by jpj on Tue Jan 18, 2022 2:01 pm, edited 1 time in total.

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: Help converting bytes to int

Post by dhylands » Mon Jan 17, 2022 11:09 pm

It would be useful to see the exact error (and the exact code) when you use

Code: Select all

if (minute == 30) and (second == 0):
I don't see anything obviously wrong with that and if I try something like this:

Code: Select all

>>> t = bytes('\x00\x1e\x08\x00\x00\x00', 'utf-8')
>>> second = t[0]&0x7f
>>> minute = t[1]&0x7f
>>> if (minute == 30) and (second == 0):
...     print('minute = 30, second = 0')
... else:
...     print('minute not = 30 or second not = 0')
... 
minute = 30, second = 0
>>> 
it seems to work fine (i2c.readfrom_mem() returns a bytes object).

jpj
Posts: 60
Joined: Sat Dec 10, 2016 3:07 pm

Re: Help converting bytes to int

Post by jpj » Mon Jan 17, 2022 11:54 pm

Thanks for the reply David. I took all the writing to LCD out to focus only on the time and "if" statement.

The program loops right over the "if minute and second" so I took out the second and just tried to match on the minute. Same result; no error and the program keeps on looping without making a match.

I wasn't certain if I was supposed to use your declaration

Code: Select all

t = bytes('\x00\x1e\x08\x00\x00\x00', 'utf-8')
so I tried it with and without, same result no match in the "if" statement:

Here is the exact code and some of the output up to where I pressed cntl-C to stop it.

Code: Select all

from lcd_api import LcdApi
from i2c_lcd import I2cLcd
from machine import I2C
from machine import Pin
from tmp102 import Tmp102
import time

# 1602 LCD 0x27
I2C_ADDR     = 0x27
I2C_NUM_ROWS = 2
I2C_NUM_COLS = 16

# DS3231 RTC 0x68
RTC_ADDR = 0x68
RTC_REGISTER = 0x00

i2c = I2C(0, sda=machine.Pin(0), scl=machine.Pin(1), freq=400000)

lcd = I2cLcd(i2c, I2C_ADDR, I2C_NUM_ROWS, I2C_NUM_COLS)

def ds3231ReadTime():
	return i2c.readfrom_mem(int(RTC_ADDR),int(RTC_REGISTER),7);

# tmp102 temperature sensor
TMP102 = Tmp102(i2c, 0x48)
tempC=0
tempF=0


if __name__ == "__main__":
    while True:
        t = ds3231ReadTime()
        second = t[0]&0x7F  #sec
        minute = t[1]&0x7F  #min
        hour   = t[2]&0x3F  #hour
        week   = t[3]&0x07  #week
        day    = t[4]&0x3F  #day
        month  = t[5]&0x1F  #month
        year   = t[6]&0x3F  #year

        print("20%x-%02x-%02x %02x:%02x:%02x" % (year,month,day,hour,minute,second))
    
        if (minute == 46):
            print('minute 46')
        else:
            print('minute not 46')
            
        time.sleep(.25)

Code: Select all

minute not 46
2022-01-17 15:45:59
minute not 46
2022-01-17 15:45:59
minute not 46
2022-01-17 15:45:59
minute not 46
2022-01-17 15:46:00
minute not 46
2022-01-17 15:46:00
minute not 46
2022-01-17 15:46:00
minute not 46
2022-01-17 15:46:00
minute not 46
2022-01-17 15:46:01
minute not 46
2022-01-17 15:46:01
minute not 46
2022-01-17 15:46:01
minute not 46
2022-01-17 15:46:01
minute not 46
2022-01-17 15:46:02
minute not 46
2022-01-17 15:46:02
minute not 46
2022-01-17 15:46:02
minute not 46
2022-01-17 15:46:02
minute not 46
2022-01-17 15:46:03
minute not 46
Traceback (most recent call last):
  File "<stdin>", line 48, in <module>
KeyboardInterrupt:

jpj
Posts: 60
Joined: Sat Dec 10, 2016 3:07 pm

Re: Help converting bytes to int

Post by jpj » Tue Jan 18, 2022 5:19 am

I kept trying different things and made a bit of progress. First I printed out the "second" with no formatting and could see the decimal numbers representing 0, 15, 30 and 45 seconds. So I coded those into my "if" statement and they worked / matched.

I realize this is not the desired method but it was revealing. Here is a copy/paste from my rshell session:

Code: Select all

MPY: soft reboot
MicroPython v1.17 on 2021-09-02; Raspberry Pi Pico with RP2040
Type "help()" for more information.
>>>
paste mode; Ctrl-C to cancel, Ctrl-D to finish
=== from machine import I2C
=== from machine import Pin
=== import time
=== # DS3231 RTC 0x68
=== RTC_ADDR = 0x68
=== RTC_REGISTER = 0x00
=== i2c = I2C(0, sda=machine.Pin(0), scl=machine.Pin(1), freq=400000)
=== def ds3231ReadTime():
===     return i2c.readfrom_mem(int(RTC_ADDR),int(RTC_REGISTER),7);
=== while True:
===     t = ds3231ReadTime()
===     second = t[0]&0x7F  #sec
===     minute = t[1]&0x7F  #min
===     hour   = t[2]&0x3F  #hour
===     print("%02x:%02x:%02x " % (hour,minute,second),end="")
===     print("{}".format(second))
===     #21:00:00 0
===     #21:00:15 21
===     #21:00:30 48
===     #20:59:45 69
===     if (second == 0) or (second == 21) or (second == 48) or (second == 69):
===         print(" MATCH ")
===     time.sleep(1)
===
21:03:43 67
21:03:44 68
21:03:45 69
 MATCH
21:03:46 70
21:03:47 71
21:03:48 72
21:03:49 73
21:03:50 80
21:03:51 81
21:03:52 82
21:03:53 83
21:03:54 84
21:03:55 85
21:03:56 86
21:03:57 87
21:03:58 88
21:03:59 89
21:04:00 0
 MATCH
21:04:01 1
21:04:02 2
21:04:03 3
21:04:04 4
21:04:05 5
21:04:06 6
21:04:07 7
21:04:08 8
21:04:09 9
21:04:10 16
21:04:11 17
21:04:12 18
21:04:13 19
21:04:14 20
21:04:15 21
 MATCH
21:04:16 22
21:04:17 23
21:04:18 24
21:04:19 25
21:04:20 32
21:04:21 33
21:04:22 34
21:04:23 35
21:04:24 36
21:04:25 37
21:04:26 38
21:04:27 39
21:04:28 40
21:04:29 41
21:04:30 48
 MATCH
21:04:31 49
Traceback (most recent call last):
  File "<stdin>", line 23, in <module>
KeyboardInterrupt:


I would still like to figure out a way to write the if statement like this:

Code: Select all

if (second == 0) or (second == 15) or (second == 30) or (second == 45):
        print(" MATCH ")
        
Thanks

User avatar
karfas
Posts: 193
Joined: Sat Jan 16, 2021 12:53 pm
Location: Vienna, Austria

Re: Help converting bytes to int

Post by karfas » Tue Jan 18, 2022 9:14 am

Maybe you shouldn't compare apples to peaches.

You are printing date+time in hex ("%02x") and wonder why they aren't equal to the decimal values in the comparison:
=== print("%02x:%02x:%02x " % (hour,minute,second),end="")
=== print("{}".format(second))
=== #20:59:45 69
=== if (second == 0) or (second == 21) or (second == 48) or (second == 69):
=== print(" MATCH ")
Edit:
The hex printout is most likely for printing the BCD encoded numbers from the DS3231.
Google found a a complete driver (including BCD decoding) at https://github.com/peterhinch/micropyth ... 31_port.py
A few hours of debugging might save you from minutes of reading the documentation! :D
My repositories: https://github.com/karfas

jpj
Posts: 60
Joined: Sat Dec 10, 2016 3:07 pm

Re: Help converting bytes to int [resolved]

Post by jpj » Tue Jan 18, 2022 2:00 pm

Using Peter Hinch's DS3231 library worked beautifully! Thank you!

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: Help converting bytes to int [resolved]

Post by dhylands » Tue Jan 18, 2022 5:40 pm

Ahh - karfas' comment makes everything clear.

I realize that you've switched libraries, but I figured this still might be useful.

The original library you were using was returning 0x15 to represent 15 seconds (i.e. BCD). 0x15 is the same as 21 decimal.

So you would have either needed to do: if (second == 0x15) rather than if (second == 15) or do a conversion when reading the seconds.

i.e. instead of second = t[0] & 0x7f, you could do second = (t[0] & 0x0f) + ((t[0] & 0x70) >> 4) * 10 and when t[0] contains 0x15 this would return 15 instead of 21.

The >> 4 is the same as / 16.

jpj
Posts: 60
Joined: Sat Dec 10, 2016 3:07 pm

Re: Help converting bytes to int [resolved]

Post by jpj » Tue Jan 18, 2022 6:52 pm

Excellent! Thank you David! And thanks for rshell too. Very useful :)

Post Reply