Page 1 of 1

Help converting bytes to int [resolved]

Posted: Mon Jan 17, 2022 8:15 pm
by jpj
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
 

Re: Help converting bytes to int

Posted: Mon Jan 17, 2022 11:09 pm
by dhylands
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).

Re: Help converting bytes to int

Posted: Mon Jan 17, 2022 11:54 pm
by jpj
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:

Re: Help converting bytes to int

Posted: Tue Jan 18, 2022 5:19 am
by jpj
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

Re: Help converting bytes to int

Posted: Tue Jan 18, 2022 9:14 am
by karfas
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

Re: Help converting bytes to int [resolved]

Posted: Tue Jan 18, 2022 2:00 pm
by jpj
Using Peter Hinch's DS3231 library worked beautifully! Thank you!

Re: Help converting bytes to int [resolved]

Posted: Tue Jan 18, 2022 5:40 pm
by dhylands
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.

Re: Help converting bytes to int [resolved]

Posted: Tue Jan 18, 2022 6:52 pm
by jpj
Excellent! Thank you David! And thanks for rshell too. Very useful :)