From 82041f162a6aa4849b230118918c09e02f8f2ed8 Mon Sep 17 00:00:00 2001 From: "davitb2013@gmail.com" Date: Sat, 22 Feb 2025 00:17:20 -0800 Subject: [PATCH 01/16] update pyproject --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 2f99784..1ecb827 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "proves-circuitpython-rv3028" -version = "1.0.0" +version = "1.0.1" description = "RV3028 device driver" readme = "README.md" requires-python = ">=3.12.3" @@ -8,6 +8,7 @@ dependencies = [ "coverage==7.6.10", "pre-commit==4.0.1", "pytest==8.3.2", + "adafruit-circuitpython-datetime==1.4.0" ] [tool.ruff.format] From 22f0be8a7016aaa29e7661ba38c614bf3a48c69c Mon Sep 17 00:00:00 2001 From: "davitb2013@gmail.com" Date: Sat, 22 Feb 2025 00:40:34 -0800 Subject: [PATCH 02/16] update get/set time --- rv3028/rv3028.py | 29 +++------ uv.lock | 161 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 169 insertions(+), 21 deletions(-) diff --git a/rv3028/rv3028.py b/rv3028/rv3028.py index d1b47d4..7be29e7 100755 --- a/rv3028/rv3028.py +++ b/rv3028/rv3028.py @@ -25,6 +25,8 @@ from adafruit_bus_device.i2c_device import I2CDevice from busio import I2C +import adafruit_datetime as dt + _RV3028_DEFAULT_ADDRESS = 0x52 @@ -108,41 +110,28 @@ def _bcd_to_int(self, bcd): def _int_to_bcd(self, value): return ((value // 10) << 4) | (value % 10) - def set_time(self, hours: int, minutes: int, seconds: int) -> None: + def set_time(self, time: dt.time) -> None: """ Sets the time on the device. This method configures the device's clock. Args: - hours (int): The hour value to set (0-23 for 24-hour format). - minutes (int): The minute value to set (0-59). - seconds (int): The second value to set (0-59). + time: A adafruit_datetime.time object representing the time to set. """ - if hours < 0 or hours > 23: - raise ValueError("Hour value must be between 0 and 23") - if minutes < 0 or minutes > 59: - raise ValueError("Minute value must be between 0 and 59") - if seconds < 0 or seconds > 59: - raise ValueError("Second vaue must be between 0 and 59") - data = bytes( [ - self._int_to_bcd(seconds), - self._int_to_bcd(minutes), - self._int_to_bcd(hours), + self._int_to_bcd(time.second), + self._int_to_bcd(time.minute), + self._int_to_bcd(time.hour), ] ) self._write_register(Reg.SECONDS, data) - def get_time(self) -> tuple[int, int, int]: + def get_time(self) -> dt.time: """ Retrieves the current time from the device. Returns: - tuple: A tuple containing the current time as (hours, minutes, seconds), - where: - hours (int): The hour value (0-23 for 24-hour format). - minutes (int): The minute value (0-59). - seconds (int): The second value (0-59). + An adafruit_datetime.time object representing the time to set. """ data = self._read_register(Reg.SECONDS, 3) return ( diff --git a/uv.lock b/uv.lock index 3173c3b..a1da050 100644 --- a/uv.lock +++ b/uv.lock @@ -1,6 +1,118 @@ version = 1 requires-python = ">=3.12.3" +[[package]] +name = "adafruit-blinka" +version = "8.54.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "adafruit-circuitpython-typing" }, + { name = "adafruit-platformdetect" }, + { name = "adafruit-pureio" }, + { name = "binho-host-adapter" }, + { name = "pyftdi" }, + { name = "sysv-ipc", marker = "platform_machine != 'mips' and sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/69/33/4f5f0074cacbd779fd35936356a40bc515e7b68d934564886f7ab5d21c80/adafruit_blinka-8.54.0.tar.gz", hash = "sha256:3c9184626e952dcd805638cd7f630b68783fd03f779bbfc9b8f1fafac8819beb", size = 253957 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4f/47/fc186df8528ae06626f3f08d669675c2adfe97b866e31015b9e2a2b85485/Adafruit_Blinka-8.54.0-py3-none-any.whl", hash = "sha256:d658ad49976b5c96c5c4583ffd29f7fe8b7b282b22835e23c1ae3a5c784fde11", size = 369441 }, +] + +[[package]] +name = "adafruit-circuitpython-busdevice" +version = "5.2.11" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "adafruit-blinka" }, + { name = "adafruit-circuitpython-typing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a2/c0/f6347ab32f077413c20f55bc4b0f1592f35affd4d26753394c5ed6c36c4c/adafruit_circuitpython_busdevice-5.2.11.tar.gz", hash = "sha256:a9a1310bee7021703ccc247bb3ff04d0873573948a6c7bee9016361cd6707a71", size = 27627 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/c7/9f0e2b2674cb5b1fb35d067a7585a2a76596a36044264eb390980d428ccf/adafruit_circuitpython_busdevice-5.2.11-py3-none-any.whl", hash = "sha256:d4379c9ae86a15f7044dea815a94525ca9eda6a7c0b2fa0e75cf9e700c9384b8", size = 7539 }, +] + +[[package]] +name = "adafruit-circuitpython-connectionmanager" +version = "3.1.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "adafruit-blinka" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/69/8b/8316002905f97a7f7e9c3a53dd9bb5a17889033ec55c403a6e55077f6298/adafruit_circuitpython_connectionmanager-3.1.3.tar.gz", hash = "sha256:0f133bdedf454ede0c0a866ed605fe166cc85f75cfcea74758e3622ae403e5f9", size = 37381 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/55/7d/896b31bd31eff89e5cab5d3acec9d3d34f5a0654ceab25e01865e628d9f9/adafruit_circuitpython_connectionmanager-3.1.3-py3-none-any.whl", hash = "sha256:9df3a4c617dae27bad1ac8607f1a084312c8498d831ebe1c6a2c8d5cb309daea", size = 7811 }, +] + +[[package]] +name = "adafruit-circuitpython-datetime" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "adafruit-blinka" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3f/1a/b04e3934004e7459a87cd64429c401b970e39d2d44b6eb0a9e14dc424ebc/adafruit_circuitpython_datetime-1.4.0.tar.gz", hash = "sha256:87caf1f2707515b245ed740694c1b1d5feb73a0e471756f2596ff8fd6e50aca6", size = 59502 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/32/dcfeb0832b2c8d591ea418fa5db816c21fe40c8017706c4943f71726301f/adafruit_circuitpython_datetime-1.4.0-py3-none-any.whl", hash = "sha256:0ccdebfaf8cee3c4ac568b5d6d94f903be83d6c1dfa0b95bd9c3ccb52ff83f31", size = 17584 }, +] + +[[package]] +name = "adafruit-circuitpython-requests" +version = "4.1.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "adafruit-blinka" }, + { name = "adafruit-circuitpython-connectionmanager" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6a/45/070129e6b77f801514cd974524c6b9fd502aa04dd5c2e45ab03e85c96cac/adafruit_circuitpython_requests-4.1.9.tar.gz", hash = "sha256:b9eeb252b43946f1a90c34ca8844e07bb1e01cd210c927f561d0e10b97c5ff9d", size = 66232 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/40/ff356fd61ef3ea044b7944687d62419c304217381ee20d9fa444aeb98339/adafruit_circuitpython_requests-4.1.9-py3-none-any.whl", hash = "sha256:d0f0a899c6ef143eab9a50a9625be43f5f8da7b9688c1496891999fa20107c93", size = 10721 }, +] + +[[package]] +name = "adafruit-circuitpython-typing" +version = "1.11.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "adafruit-blinka" }, + { name = "adafruit-circuitpython-busdevice" }, + { name = "adafruit-circuitpython-requests" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/24/80/8c280fa7d42a23dce40b2fe64f708d18fa32b384adbf6934955d2c2ebecf/adafruit_circuitpython_typing-1.11.2.tar.gz", hash = "sha256:c7ac8532a9ad7e4a65d5588764b7483c0b6967d305c37faebcc0c5356d677e33", size = 29277 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dd/d5/76a6bca9cf08907b48dfc8ccbccbd190155353f521876e02d6b7bb244003/adafruit_circuitpython_typing-1.11.2-py3-none-any.whl", hash = "sha256:e1401a09bbfdf67e43875cc6755b3af0eda8381b12c9c8f759bd7676b7425e1c", size = 11101 }, +] + +[[package]] +name = "adafruit-platformdetect" +version = "3.77.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6b/4e/2b2ca031227de47e2aab6cf092b78934c9c0033a685075ddab3e0c0b55fe/adafruit_platformdetect-3.77.0.tar.gz", hash = "sha256:adce6386059637e92b4cb5d3430d016119cd3eb19f9276920c54515f3d798949", size = 48024 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/30/18/b18e9ff2aee42f03082675c5d18d4eb02411477e07c86d74833d3396792e/Adafruit_PlatformDetect-3.77.0-py3-none-any.whl", hash = "sha256:93f599c21e7db2d92bc32ac69ba5063876404c4af87d11358863e62f407409be", size = 25542 }, +] + +[[package]] +name = "adafruit-pureio" +version = "1.1.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e5/b7/f1672435116822079bbdab42163f9e6424769b7db778873d95d18c085230/Adafruit_PureIO-1.1.11.tar.gz", hash = "sha256:c4cfbb365731942d1f1092a116f47dfdae0aef18c5b27f1072b5824ad5ea8c7c", size = 35511 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/19/9d/28e9d12f36e13c5f2acba3098187b0e931290ecd1d8df924391b5ad2db19/Adafruit_PureIO-1.1.11-py3-none-any.whl", hash = "sha256:281ab2099372cc0decc26326918996cbf21b8eed694ec4764d51eefa029d324e", size = 10678 }, +] + +[[package]] +name = "binho-host-adapter" +version = "0.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyserial" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/68/36/29b7b896e83e195fac6d64ccff95c0f24a18ee86e7437a22e60e0331d90a/binho-host-adapter-0.1.6.tar.gz", hash = "sha256:1e6da7a84e208c13b5f489066f05774bff1d593d0f5bf1ca149c2b8e83eae856", size = 10068 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/6b/0f13486003aea3eb349c2946b7ec9753e7558b78e35d22c938062a96959c/binho_host_adapter-0.1.6-py3-none-any.whl", hash = "sha256:f71ca176c1e2fc1a5dce128beb286da217555c6c7c805f2ed282a6f3507ec277", size = 10540 }, +] + [[package]] name = "cfgv" version = "3.4.0" @@ -147,9 +259,10 @@ wheels = [ [[package]] name = "proves-circuitpython-rv3028" -version = "1.0.0" +version = "1.0.1" source = { virtual = "." } dependencies = [ + { name = "adafruit-circuitpython-datetime" }, { name = "coverage" }, { name = "pre-commit" }, { name = "pytest" }, @@ -157,11 +270,33 @@ dependencies = [ [package.metadata] requires-dist = [ + { name = "adafruit-circuitpython-datetime", specifier = "==1.4.0" }, { name = "coverage", specifier = "==7.6.10" }, { name = "pre-commit", specifier = "==4.0.1" }, { name = "pytest", specifier = "==8.3.2" }, ] +[[package]] +name = "pyftdi" +version = "0.56.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyserial" }, + { name = "pyusb" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/96/a8de7b7e5556d4b00d1ca1969fc34c89a1b6d177876c7a31d42631b090fc/pyftdi-0.56.0-py3-none-any.whl", hash = "sha256:3ef0baadbf9031dde9d623ae66fac2d16ded36ce1b66c17765ca1944cb38b8b0", size = 145718 }, +] + +[[package]] +name = "pyserial" +version = "3.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1e/7d/ae3f0a63f41e4d2f6cb66a5b57197850f919f59e558159a4dd3a818f5082/pyserial-3.5.tar.gz", hash = "sha256:3c77e014170dfffbd816e6ffc205e9842efb10be9f58ec16d3e8675b4925cddb", size = 159125 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/bc/587a445451b253b285629263eb51c2d8e9bcea4fc97826266d186f96f558/pyserial-3.5-py2.py3-none-any.whl", hash = "sha256:c4451db6ba391ca6ca299fb3ec7bae67a5c55dde170964c7a14ceefec02f2cf0", size = 90585 }, +] + [[package]] name = "pytest" version = "8.3.2" @@ -177,6 +312,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0f/f9/cf155cf32ca7d6fa3601bc4c5dd19086af4b320b706919d48a4c79081cf9/pytest-8.3.2-py3-none-any.whl", hash = "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5", size = 341802 }, ] +[[package]] +name = "pyusb" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/00/6b/ce3727395e52b7b76dfcf0c665e37d223b680b9becc60710d4bc08b7b7cb/pyusb-1.3.1.tar.gz", hash = "sha256:3af070b607467c1c164f49d5b0caabe8ac78dbed9298d703a8dbf9df4052d17e", size = 77281 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/28/b8/27e6312e86408a44fe16bd28ee12dd98608b39f7e7e57884a24e8f29b573/pyusb-1.3.1-py3-none-any.whl", hash = "sha256:bf9b754557af4717fe80c2b07cc2b923a9151f5c08d17bdb5345dac09d6a0430", size = 58465 }, +] + [[package]] name = "pyyaml" version = "6.0.2" @@ -203,6 +347,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 }, ] +[[package]] +name = "sysv-ipc" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0c/d7/5d2f861155e9749f981e6c58f2a482d3ab458bf8c35ae24d4b4d5899ebf9/sysv_ipc-1.1.0.tar.gz", hash = "sha256:0f063cbd36ec232032e425769ebc871f195a7d183b9af32f9901589ea7129ac3", size = 99448 } + +[[package]] +name = "typing-extensions" +version = "4.12.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, +] + [[package]] name = "virtualenv" version = "20.29.1" From 0e74fd7390308f2f80a7a99d07ca10beee9bddb0 Mon Sep 17 00:00:00 2001 From: "davitb2013@gmail.com" Date: Sat, 22 Feb 2025 00:46:44 -0800 Subject: [PATCH 03/16] update time tests --- rv3028/rv3028.py | 8 ++++---- tests/test_RV3028.py | 13 ++++++++----- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/rv3028/rv3028.py b/rv3028/rv3028.py index 7be29e7..8dcb093 100755 --- a/rv3028/rv3028.py +++ b/rv3028/rv3028.py @@ -134,10 +134,10 @@ def get_time(self) -> dt.time: An adafruit_datetime.time object representing the time to set. """ data = self._read_register(Reg.SECONDS, 3) - return ( - self._bcd_to_int(data[2]), # hours - self._bcd_to_int(data[1]), # minutes - self._bcd_to_int(data[0]), # seconds + return dt.time( + hour=self._bcd_to_int(data[2]), + minute=self._bcd_to_int(data[1]), + second=self._bcd_to_int(data[0]), ) def set_date(self, year: int, month: int, date: int, weekday: int) -> None: diff --git a/tests/test_RV3028.py b/tests/test_RV3028.py index a5dd7d0..aa7cbed 100644 --- a/tests/test_RV3028.py +++ b/tests/test_RV3028.py @@ -1,3 +1,4 @@ +import adafruit_datetime as dt import pytest from mocks.i2cMock import MockI2C, MockI2CDevice @@ -25,11 +26,13 @@ def rtc(): # Test functions def test_set_and_get_time(rtc): - rtc.set_time(23, 59, 58) - hours, minutes, seconds = rtc.get_time() - assert hours == 23 - assert minutes == 59 - assert seconds == 58 + time_to_set = dt.time(hour=23, minute=59, second=58) + rtc.set_time(time_to_set) + + time_to_check = rtc.get_time() + assert time_to_check.hour == 23 + assert time_to_check.minute == 59 + assert time_to_check.second == 58 def test_set_and_get_date(rtc): From 3eba72c37e7cf02ed9a5d7a2fefe28a1c4612681 Mon Sep 17 00:00:00 2001 From: "davitb2013@gmail.com" Date: Sat, 22 Feb 2025 01:04:45 -0800 Subject: [PATCH 04/16] get and set date --- rv3028/rv3028.py | 46 +++++++++++++------------------------------- tests/test_RV3028.py | 14 ++++++++------ 2 files changed, 21 insertions(+), 39 deletions(-) diff --git a/rv3028/rv3028.py b/rv3028/rv3028.py index 8dcb093..e091583 100755 --- a/rv3028/rv3028.py +++ b/rv3028/rv3028.py @@ -30,16 +30,6 @@ _RV3028_DEFAULT_ADDRESS = 0x52 -class WEEKDAY: - SUNDAY = 0 - MONDAY = 1 - TUESDAY = 2 - WEDNESDAY = 3 - THURSDAY = 4 - FRIDAY = 5 - SATURDAY = 6 - - class RV3028: def __init__(self, i2c, address: int = _RV3028_DEFAULT_ADDRESS): if isinstance(i2c, I2C): @@ -140,38 +130,29 @@ def get_time(self) -> dt.time: second=self._bcd_to_int(data[0]), ) - def set_date(self, year: int, month: int, date: int, weekday: int) -> None: + def set_date(self, date: dt.date) -> None: """ Sets the date of the device. Args: - year (int): The year value to set - month (int): The month value to set (1-12). - date (int): The date value to set (1-31). - weekday (int): The day of the week to set (0-6, where 0 represents Sunday). + date: A adafruit_datetime.date object representing the date to set. """ - if year < 0 or year > 99: - raise ValueError("Year value must be between 0 and 99") - if month < 1 or month > 12: - raise ValueError("Month value must be between 1 and 12") - if date < 1 or date > 31: - raise ValueError("Date value must be between 1 and 31") - if weekday < 0 or weekday > 6: - raise ValueError("Weekday value must be between 0 and 6") + if date.year < 2000 or date.year > 2099: + raise ValueError("Year value must be between 2000 and 2099") data = bytes( [ - self._int_to_bcd(weekday), - self._int_to_bcd(date), - self._int_to_bcd(month), - self._int_to_bcd(year), + self._int_to_bcd(date.weekday()), + self._int_to_bcd(date.day), + self._int_to_bcd(date.month), + self._int_to_bcd(date.year - 2000), ] ) self._write_register( Reg.WEEKDAY, data ) # this is a weird way to do it but it works - def get_date(self) -> tuple[int, int, int, int]: + def get_date(self) -> dt.date: """ Gets the date of the device. @@ -183,11 +164,10 @@ def get_date(self) -> tuple[int, int, int, int]: weekday (int): The day of the week (0-6, where 0 represents Sunday). """ data = self._read_register(Reg.WEEKDAY, 4) - return ( - self._bcd_to_int(data[3]), # year - self._bcd_to_int(data[2]), # month - self._bcd_to_int(data[1]), # date - self._bcd_to_int(data[0]), # weekday + return dt.date( + year=self._bcd_to_int(data[3]) + 2000, + month=self._bcd_to_int(data[2]), + day=self._bcd_to_int(data[1]), ) def set_alarm( diff --git a/tests/test_RV3028.py b/tests/test_RV3028.py index aa7cbed..e5a8a8b 100644 --- a/tests/test_RV3028.py +++ b/tests/test_RV3028.py @@ -36,12 +36,14 @@ def test_set_and_get_time(rtc): def test_set_and_get_date(rtc): - rtc.set_date(21, 12, 31, 5) # Year, month, date, weekday - year, month, date, weekday = rtc.get_date() - assert year == 21 - assert month == 12 - assert date == 31 - assert weekday == 5 + date_to_set = dt.date(year=2021, month=12, day=31) + rtc.set_date(date_to_set) + + date_to_check = rtc.get_date() + assert date_to_check.year == 2021 + assert date_to_check.month == 12 + assert date_to_check.day == 31 + assert date_to_check.weekday() == 4 def test_set_flag(rtc): From d9bce6c21431f3bb3f7e73c3a29e56f0022e67f6 Mon Sep 17 00:00:00 2001 From: "davitb2013@gmail.com" Date: Sat, 22 Feb 2025 01:20:24 -0800 Subject: [PATCH 05/16] use properties for time and date --- rv3028/rv3028.py | 60 +++++++++++++++++++++++--------------------- tests/test_RV3028.py | 8 +++--- 2 files changed, 36 insertions(+), 32 deletions(-) diff --git a/rv3028/rv3028.py b/rv3028/rv3028.py index e091583..b3595ed 100755 --- a/rv3028/rv3028.py +++ b/rv3028/rv3028.py @@ -100,7 +100,23 @@ def _bcd_to_int(self, bcd): def _int_to_bcd(self, value): return ((value // 10) << 4) | (value % 10) - def set_time(self, time: dt.time) -> None: + @property + def time(self) -> dt.time: + """ + Retrieves the current time from the device. + + Returns: + An adafruit_datetime.time object representing the time to set. + """ + data = self._read_register(Reg.SECONDS, 3) + return dt.time( + hour=self._bcd_to_int(data[2]), + minute=self._bcd_to_int(data[1]), + second=self._bcd_to_int(data[0]), + ) + + @time.setter + def time(self, time: dt.time) -> None: """ Sets the time on the device. This method configures the device's clock. @@ -116,21 +132,27 @@ def set_time(self, time: dt.time) -> None: ) self._write_register(Reg.SECONDS, data) - def get_time(self) -> dt.time: + @property + def date(self) -> dt.date: """ - Retrieves the current time from the device. + Gets the date of the device. Returns: - An adafruit_datetime.time object representing the time to set. + tuple: A 4-tuple (year, month, date, weekday) where: + year (int): The year value (0-99). + month (int): The month value (1-12). + date (int): The date value (1-31). + weekday (int): The day of the week (0-6, where 0 represents Sunday). """ - data = self._read_register(Reg.SECONDS, 3) - return dt.time( - hour=self._bcd_to_int(data[2]), - minute=self._bcd_to_int(data[1]), - second=self._bcd_to_int(data[0]), + data = self._read_register(Reg.WEEKDAY, 4) + return dt.date( + year=self._bcd_to_int(data[3]) + 2000, + month=self._bcd_to_int(data[2]), + day=self._bcd_to_int(data[1]), ) - def set_date(self, date: dt.date) -> None: + @date.setter + def date(self, date: dt.date) -> None: """ Sets the date of the device. @@ -152,24 +174,6 @@ def set_date(self, date: dt.date) -> None: Reg.WEEKDAY, data ) # this is a weird way to do it but it works - def get_date(self) -> dt.date: - """ - Gets the date of the device. - - Returns: - tuple: A 4-tuple (year, month, date, weekday) where: - year (int): The year value (0-99). - month (int): The month value (1-12). - date (int): The date value (1-31). - weekday (int): The day of the week (0-6, where 0 represents Sunday). - """ - data = self._read_register(Reg.WEEKDAY, 4) - return dt.date( - year=self._bcd_to_int(data[3]) + 2000, - month=self._bcd_to_int(data[2]), - day=self._bcd_to_int(data[1]), - ) - def set_alarm( self, minute: int = None, hour: int = None, weekday: int = None ) -> None: diff --git a/tests/test_RV3028.py b/tests/test_RV3028.py index e5a8a8b..a873614 100644 --- a/tests/test_RV3028.py +++ b/tests/test_RV3028.py @@ -27,9 +27,9 @@ def rtc(): # Test functions def test_set_and_get_time(rtc): time_to_set = dt.time(hour=23, minute=59, second=58) - rtc.set_time(time_to_set) + rtc.time = time_to_set - time_to_check = rtc.get_time() + time_to_check = rtc.time assert time_to_check.hour == 23 assert time_to_check.minute == 59 assert time_to_check.second == 58 @@ -37,9 +37,9 @@ def test_set_and_get_time(rtc): def test_set_and_get_date(rtc): date_to_set = dt.date(year=2021, month=12, day=31) - rtc.set_date(date_to_set) + rtc.date = date_to_set - date_to_check = rtc.get_date() + date_to_check = rtc.date assert date_to_check.year == 2021 assert date_to_check.month == 12 assert date_to_check.day == 31 From c5f0eb7d64d5e737a301901bcc640ed494344ece Mon Sep 17 00:00:00 2001 From: "davitb2013@gmail.com" Date: Sat, 22 Feb 2025 01:35:39 -0800 Subject: [PATCH 06/16] add datetime property --- rv3028/rv3028.py | 22 ++++++++++++++++++++++ tests/test_RV3028.py | 32 ++++++++++++++++++++++++++++---- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/rv3028/rv3028.py b/rv3028/rv3028.py index b3595ed..8dd7f3c 100755 --- a/rv3028/rv3028.py +++ b/rv3028/rv3028.py @@ -174,6 +174,28 @@ def date(self, date: dt.date) -> None: Reg.WEEKDAY, data ) # this is a weird way to do it but it works + @property + def datetime(self) -> dt.datetime: + """ + Get the current date and time as a combined datetime object. + + Returns: + adafruit_datetime.datetime: The current date and time. + """ + return dt.datetime.combine(self.date, self.time) + + @datetime.setter + def datetime(self, datetime: dt.datetime | str) -> None: + """ + Set the date and time for the RV3028. + + Args: + datetime (adafruit_datetime.datetime | str): A datetime object + """ + + self.time = datetime.time() + self.date = datetime.date() + def set_alarm( self, minute: int = None, hour: int = None, weekday: int = None ) -> None: diff --git a/tests/test_RV3028.py b/tests/test_RV3028.py index a873614..e7c5401 100644 --- a/tests/test_RV3028.py +++ b/tests/test_RV3028.py @@ -26,8 +26,7 @@ def rtc(): # Test functions def test_set_and_get_time(rtc): - time_to_set = dt.time(hour=23, minute=59, second=58) - rtc.time = time_to_set + rtc.time = dt.time(hour=23, minute=59, second=58) time_to_check = rtc.time assert time_to_check.hour == 23 @@ -36,8 +35,7 @@ def test_set_and_get_time(rtc): def test_set_and_get_date(rtc): - date_to_set = dt.date(year=2021, month=12, day=31) - rtc.date = date_to_set + rtc.date = dt.date(year=2021, month=12, day=31) date_to_check = rtc.date assert date_to_check.year == 2021 @@ -46,6 +44,32 @@ def test_set_and_get_date(rtc): assert date_to_check.weekday() == 4 +def test_year_bounds_on_set_date(rtc): + # Test setting a date with a year below the lower bound (2000) + with pytest.raises(ValueError): + rtc.date = dt.date(year=1999, month=12, day=31) + + # Test setting a date with a year above the upper bound (2099) + with pytest.raises(ValueError): + rtc.date = dt.date(year=2100, month=1, day=1) + + +def test_set_and_get_datetime(rtc): + datetime_to_set = dt.datetime( + year=2028, month=11, day=30, hour=11, minute=11, second=12 + ) + rtc.datetime = datetime_to_set + + datetime_to_check = rtc.datetime + assert datetime_to_check.year == 2028 + assert datetime_to_check.month == 11 + assert datetime_to_check.day == 30 + assert datetime_to_check.hour == 11 + assert datetime_to_check.minute == 11 + assert datetime_to_check.second == 12 + assert datetime_to_check.weekday() == 3 + + def test_set_flag(rtc): # Check if _set_flag raises a ValueError with pytest.raises(ValueError): From 8cc579b9c17626e158ff7dc6282664375b394245 Mon Sep 17 00:00:00 2001 From: "davitb2013@gmail.com" Date: Thu, 27 Feb 2025 19:14:12 -0800 Subject: [PATCH 07/16] basic time class --- rv3028/datetime.py | 64 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 rv3028/datetime.py diff --git a/rv3028/datetime.py b/rv3028/datetime.py new file mode 100644 index 0000000..5e3f9ab --- /dev/null +++ b/rv3028/datetime.py @@ -0,0 +1,64 @@ +""" +Basic date and time formatting library for RV-3028-C7 RTC module. + +Author: Davit Babayan +""" + +_MONTH_DAYS = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) + + +def _is_leap_year(year: int) -> bool: + "year -> True if leap year, else False." + return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0) + + +def _validate_times(hour: int, minute: int, second: int) -> None: + if not (0 <= hour <= 23): + raise ValueError("Hour must be in 0..24") + if not (0 <= minute <= 59): + raise ValueError("Minute must be in 0..59") + if not (0 <= second <= 59): + raise ValueError("Second must be in 0..59") + + +def _validate_dates(year: int, month: int, day: int) -> None: + if not (2000 <= year <= 2099): + raise ValueError("Year must be in 2000..2099") + if not (1 <= month <= 12): + raise ValueError("Month must be in 1..12") + if month == 2 and _is_leap_year(year): + if not (1 <= day <= 29): + raise ValueError("Day must be in 1..29") + elif not (1 <= day <= _MONTH_DAYS[month - 1]): + raise ValueError(f"Day must be in 1..{_MONTH_DAYS[month - 1]}") + + +class rtime: + """ + Class that represents time in hours, minutes and seconds. + + Attributes: + hour (int): The hour of the time. + minute (int): The minute of the time. + second (int): The second of the time. + """ + + def __new__(cls, hour: int, minute: int, second: int) -> "rtime": + _validate_times(hour, minute, second) + self = super().__new__(cls) + self._hour = hour + self._minute = minute + self._second = second + return self + + @property + def hour(self) -> int: + return self._hour + + @property + def minute(self) -> int: + return self._minute + + @property + def second(self) -> int: + return self._second From cb6660303533dc15f9b2d5dedcaa85cd9493a1d4 Mon Sep 17 00:00:00 2001 From: "davitb2013@gmail.com" Date: Thu, 27 Feb 2025 19:16:58 -0800 Subject: [PATCH 08/16] basic date class --- rv3028/datetime.py | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/rv3028/datetime.py b/rv3028/datetime.py index 5e3f9ab..b5624e7 100644 --- a/rv3028/datetime.py +++ b/rv3028/datetime.py @@ -51,6 +51,11 @@ def __new__(cls, hour: int, minute: int, second: int) -> "rtime": self._second = second return self + def __repr__(self) -> str: + return f"{self.hour}:{self.minute}:{self.second}" + + __str__ = __repr__ + @property def hour(self) -> int: return self._hour @@ -62,3 +67,39 @@ def minute(self) -> int: @property def second(self) -> int: return self._second + + +class rdate: + """ + Class that represents date in year, month and day. + + Attributes: + year (int): The year of the date. + month (int): The month of the date. + day (int): The day of the date. + """ + + def __new__(cls, year: int, month: int, day: int) -> "rdate": + _validate_dates(year, month, day) + self = super().__new__(cls) + self._year = year + self._month = month + self._day = day + return self + + def __repr__(self) -> str: + return f"{self.year}-{self.month}-{self.day}" + + __str__ = __repr__ + + @property + def year(self) -> int: + return self._year + + @property + def month(self) -> int: + return self._month + + @property + def day(self) -> int: + return self._day From 44f36b990e749b1039d40f9a01551730a9fe87ab Mon Sep 17 00:00:00 2001 From: "davitb2013@gmail.com" Date: Thu, 27 Feb 2025 19:23:34 -0800 Subject: [PATCH 09/16] basic datetime class --- rv3028/datetime.py | 57 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/rv3028/datetime.py b/rv3028/datetime.py index b5624e7..9dda678 100644 --- a/rv3028/datetime.py +++ b/rv3028/datetime.py @@ -103,3 +103,60 @@ def month(self) -> int: @property def day(self) -> int: return self._day + + +class rdatetime: + """ + Class that represents date and time combined. + + Attributes: + year (int): The year of the datetime. + month (int): The month of the datetime. + day (int): The day of the datetime. + hour (int): The hour of the datetime. + minute (int): The minute of the datetime. + second (int): The second of the datetime. + """ + + def __new__( + cls, year: int, month: int, day: int, hour: int, minute: int, second: int + ) -> "rdatetime": + _validate_dates(year, month, day) + _validate_times(hour, minute, second) + self = object().__new__(cls) + self._year = year + self._month = month + self._day = day + self._second = second + self._minute = minute + self._hour = hour + return self + + def __repr__(self) -> str: + return f"{self.year}-{self.month:02d}-{self.day:02d} {self.hour:02d}:{self.minute:02d}:{self.second:02d}" + + __str__ = __repr__ + + @property + def year(self) -> int: + return self._year + + @property + def month(self) -> int: + return self._month + + @property + def day(self) -> int: + return self._day + + @property + def hour(self) -> int: + return self._hour + + @property + def minute(self) -> int: + return self._minute + + @property + def second(self) -> int: + return self._second From 9e9409e0c3fb569eeb8058db5e13fd2c0c458980 Mon Sep 17 00:00:00 2001 From: "davitb2013@gmail.com" Date: Thu, 27 Feb 2025 20:04:30 -0800 Subject: [PATCH 10/16] remove weekdays --- rv3028/{datetime.py => rdatetime.py} | 24 ++++++++++++++++-------- rv3028/rv3028.py | 15 ++++++--------- tests/test_RV3028.py | 4 +--- 3 files changed, 23 insertions(+), 20 deletions(-) rename rv3028/{datetime.py => rdatetime.py} (88%) diff --git a/rv3028/datetime.py b/rv3028/rdatetime.py similarity index 88% rename from rv3028/datetime.py rename to rv3028/rdatetime.py index 9dda678..b8dace2 100644 --- a/rv3028/datetime.py +++ b/rv3028/rdatetime.py @@ -1,7 +1,5 @@ """ Basic date and time formatting library for RV-3028-C7 RTC module. - -Author: Davit Babayan """ _MONTH_DAYS = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) @@ -33,7 +31,7 @@ def _validate_dates(year: int, month: int, day: int) -> None: raise ValueError(f"Day must be in 1..{_MONTH_DAYS[month - 1]}") -class rtime: +class time: """ Class that represents time in hours, minutes and seconds. @@ -43,7 +41,7 @@ class rtime: second (int): The second of the time. """ - def __new__(cls, hour: int, minute: int, second: int) -> "rtime": + def __new__(cls, hour: int, minute: int, second: int) -> "time": _validate_times(hour, minute, second) self = super().__new__(cls) self._hour = hour @@ -69,7 +67,7 @@ def second(self) -> int: return self._second -class rdate: +class date: """ Class that represents date in year, month and day. @@ -79,7 +77,7 @@ class rdate: day (int): The day of the date. """ - def __new__(cls, year: int, month: int, day: int) -> "rdate": + def __new__(cls, year: int, month: int, day: int) -> "date": _validate_dates(year, month, day) self = super().__new__(cls) self._year = year @@ -105,7 +103,7 @@ def day(self) -> int: return self._day -class rdatetime: +class datetime: """ Class that represents date and time combined. @@ -120,7 +118,7 @@ class rdatetime: def __new__( cls, year: int, month: int, day: int, hour: int, minute: int, second: int - ) -> "rdatetime": + ) -> "datetime": _validate_dates(year, month, day) _validate_times(hour, minute, second) self = object().__new__(cls) @@ -132,6 +130,10 @@ def __new__( self._hour = hour return self + @classmethod + def combine(cls, date: date, time: time) -> "datetime": + return cls(date.year, date.month, date.day, time.hour, time.minute, time.second) + def __repr__(self) -> str: return f"{self.year}-{self.month:02d}-{self.day:02d} {self.hour:02d}:{self.minute:02d}:{self.second:02d}" @@ -160,3 +162,9 @@ def minute(self) -> int: @property def second(self) -> int: return self._second + + def time(self) -> time: + return time(self.hour, self.minute, self.second) + + def date(self) -> date: + return date(self.year, self.month, self.day) diff --git a/rv3028/rv3028.py b/rv3028/rv3028.py index 8dd7f3c..f99e03a 100755 --- a/rv3028/rv3028.py +++ b/rv3028/rv3028.py @@ -4,6 +4,7 @@ Authors: Nicole Maggard, Michael Pham, and Rachel Sarmiento """ +import rv3028.rdatetime as dt from rv3028.registers import ( BSM, EECMD, @@ -25,7 +26,6 @@ from adafruit_bus_device.i2c_device import I2CDevice from busio import I2C -import adafruit_datetime as dt _RV3028_DEFAULT_ADDRESS = 0x52 @@ -144,11 +144,11 @@ def date(self) -> dt.date: date (int): The date value (1-31). weekday (int): The day of the week (0-6, where 0 represents Sunday). """ - data = self._read_register(Reg.WEEKDAY, 4) + data = self._read_register(Reg.DATE, 3) return dt.date( - year=self._bcd_to_int(data[3]) + 2000, - month=self._bcd_to_int(data[2]), - day=self._bcd_to_int(data[1]), + year=self._bcd_to_int(data[2]) + 2000, + month=self._bcd_to_int(data[1]), + day=self._bcd_to_int(data[0]), ) @date.setter @@ -159,19 +159,16 @@ def date(self, date: dt.date) -> None: Args: date: A adafruit_datetime.date object representing the date to set. """ - if date.year < 2000 or date.year > 2099: - raise ValueError("Year value must be between 2000 and 2099") data = bytes( [ - self._int_to_bcd(date.weekday()), self._int_to_bcd(date.day), self._int_to_bcd(date.month), self._int_to_bcd(date.year - 2000), ] ) self._write_register( - Reg.WEEKDAY, data + Reg.DATE, data ) # this is a weird way to do it but it works @property diff --git a/tests/test_RV3028.py b/tests/test_RV3028.py index e7c5401..27fff1b 100644 --- a/tests/test_RV3028.py +++ b/tests/test_RV3028.py @@ -1,7 +1,7 @@ -import adafruit_datetime as dt import pytest from mocks.i2cMock import MockI2C, MockI2CDevice +import rv3028.rdatetime as dt from rv3028.registers import ( BSM, Alarm, @@ -41,7 +41,6 @@ def test_set_and_get_date(rtc): assert date_to_check.year == 2021 assert date_to_check.month == 12 assert date_to_check.day == 31 - assert date_to_check.weekday() == 4 def test_year_bounds_on_set_date(rtc): @@ -67,7 +66,6 @@ def test_set_and_get_datetime(rtc): assert datetime_to_check.hour == 11 assert datetime_to_check.minute == 11 assert datetime_to_check.second == 12 - assert datetime_to_check.weekday() == 3 def test_set_flag(rtc): From 54b88ecf6c56b4666a2d3775a51b315394b33a81 Mon Sep 17 00:00:00 2001 From: "davitb2013@gmail.com" Date: Thu, 27 Feb 2025 20:08:01 -0800 Subject: [PATCH 11/16] update docs --- rv3028/{rdatetime.py => rtc_datetime.py} | 0 rv3028/rv3028.py | 18 +++++++----------- tests/test_RV3028.py | 2 +- 3 files changed, 8 insertions(+), 12 deletions(-) rename rv3028/{rdatetime.py => rtc_datetime.py} (100%) diff --git a/rv3028/rdatetime.py b/rv3028/rtc_datetime.py similarity index 100% rename from rv3028/rdatetime.py rename to rv3028/rtc_datetime.py diff --git a/rv3028/rv3028.py b/rv3028/rv3028.py index f99e03a..97b5c4d 100755 --- a/rv3028/rv3028.py +++ b/rv3028/rv3028.py @@ -4,7 +4,7 @@ Authors: Nicole Maggard, Michael Pham, and Rachel Sarmiento """ -import rv3028.rdatetime as dt +import rv3028.rtc_datetime as dt from rv3028.registers import ( BSM, EECMD, @@ -106,7 +106,7 @@ def time(self) -> dt.time: Retrieves the current time from the device. Returns: - An adafruit_datetime.time object representing the time to set. + An rtc_datetime.time object representing the time to set. """ data = self._read_register(Reg.SECONDS, 3) return dt.time( @@ -121,7 +121,7 @@ def time(self, time: dt.time) -> None: Sets the time on the device. This method configures the device's clock. Args: - time: A adafruit_datetime.time object representing the time to set. + time: A rtc_datetime.time object representing the time to set. """ data = bytes( [ @@ -138,11 +138,7 @@ def date(self) -> dt.date: Gets the date of the device. Returns: - tuple: A 4-tuple (year, month, date, weekday) where: - year (int): The year value (0-99). - month (int): The month value (1-12). - date (int): The date value (1-31). - weekday (int): The day of the week (0-6, where 0 represents Sunday). + An rtc_datetime.date object representing the date. """ data = self._read_register(Reg.DATE, 3) return dt.date( @@ -157,7 +153,7 @@ def date(self, date: dt.date) -> None: Sets the date of the device. Args: - date: A adafruit_datetime.date object representing the date to set. + date: A rtc_datetime.date object representing the date to set. """ data = bytes( @@ -177,7 +173,7 @@ def datetime(self) -> dt.datetime: Get the current date and time as a combined datetime object. Returns: - adafruit_datetime.datetime: The current date and time. + rtc_datetime.datetime: The current date and time. """ return dt.datetime.combine(self.date, self.time) @@ -187,7 +183,7 @@ def datetime(self, datetime: dt.datetime | str) -> None: Set the date and time for the RV3028. Args: - datetime (adafruit_datetime.datetime | str): A datetime object + datetime (rtc_datetime.datetime): A datetime object """ self.time = datetime.time() diff --git a/tests/test_RV3028.py b/tests/test_RV3028.py index 27fff1b..6447d6a 100644 --- a/tests/test_RV3028.py +++ b/tests/test_RV3028.py @@ -1,7 +1,7 @@ import pytest from mocks.i2cMock import MockI2C, MockI2CDevice -import rv3028.rdatetime as dt +import rv3028.rtc_datetime as dt from rv3028.registers import ( BSM, Alarm, From 7b7e5fd380608b1e0d80a3d500537289a86a75c8 Mon Sep 17 00:00:00 2001 From: "davitb2013@gmail.com" Date: Thu, 27 Feb 2025 21:06:17 -0800 Subject: [PATCH 12/16] fixup --- rv3028/rtc_datetime.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rv3028/rtc_datetime.py b/rv3028/rtc_datetime.py index b8dace2..cbc2609 100644 --- a/rv3028/rtc_datetime.py +++ b/rv3028/rtc_datetime.py @@ -43,7 +43,7 @@ class time: def __new__(cls, hour: int, minute: int, second: int) -> "time": _validate_times(hour, minute, second) - self = super().__new__(cls) + self = object.__new__(cls) self._hour = hour self._minute = minute self._second = second @@ -79,7 +79,7 @@ class date: def __new__(cls, year: int, month: int, day: int) -> "date": _validate_dates(year, month, day) - self = super().__new__(cls) + self = object.__new__(cls) self._year = year self._month = month self._day = day @@ -121,7 +121,7 @@ def __new__( ) -> "datetime": _validate_dates(year, month, day) _validate_times(hour, minute, second) - self = object().__new__(cls) + self = object.__new__(cls) self._year = year self._month = month self._day = day From d4118a756597913ebc3ed7f91b03a90dd194afe6 Mon Sep 17 00:00:00 2001 From: "davitb2013@gmail.com" Date: Thu, 27 Feb 2025 21:21:07 -0800 Subject: [PATCH 13/16] add unit tests --- pyproject.toml | 1 + rv3028/rtc_datetime.py | 6 +-- tests/test_rtc_datetime.py | 81 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 tests/test_rtc_datetime.py diff --git a/pyproject.toml b/pyproject.toml index 1ecb827..2515eb0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,6 +28,7 @@ skip_covered = false include = [ "rv3028/registers.py", "rv3028/rv3028.py", + "rv3028/rtc_datetime.py", ] [tool.coverage.html] diff --git a/rv3028/rtc_datetime.py b/rv3028/rtc_datetime.py index cbc2609..97ec60e 100644 --- a/rv3028/rtc_datetime.py +++ b/rv3028/rtc_datetime.py @@ -27,8 +27,8 @@ def _validate_dates(year: int, month: int, day: int) -> None: if month == 2 and _is_leap_year(year): if not (1 <= day <= 29): raise ValueError("Day must be in 1..29") - elif not (1 <= day <= _MONTH_DAYS[month - 1]): - raise ValueError(f"Day must be in 1..{_MONTH_DAYS[month - 1]}") + elif not (1 <= day <= _MONTH_DAYS[month - 1]): + raise ValueError(f"Day must be in 1..{_MONTH_DAYS[month - 1]}") class time: @@ -50,7 +50,7 @@ def __new__(cls, hour: int, minute: int, second: int) -> "time": return self def __repr__(self) -> str: - return f"{self.hour}:{self.minute}:{self.second}" + return f"{self.hour:2d}:{self.minute:2d}:{self.second:2d}" __str__ = __repr__ diff --git a/tests/test_rtc_datetime.py b/tests/test_rtc_datetime.py new file mode 100644 index 0000000..f90c2fa --- /dev/null +++ b/tests/test_rtc_datetime.py @@ -0,0 +1,81 @@ +import pytest +from mocks.i2cMock import MockI2C, MockI2CDevice + +import rv3028.rtc_datetime as dt +from rv3028.rv3028 import RV3028 + + +@pytest.fixture +def rtc(): + i2c_bus = MockI2C() + i2c_device = MockI2CDevice(i2c_bus, 0x52) + rtc = RV3028(i2c_device) + return rtc + + +# Test functions +def test_leap_year(): + assert dt._is_leap_year(2000) + assert not dt._is_leap_year(2001) + assert not dt._is_leap_year(2100) + assert dt._is_leap_year(2004) + + +def test_validate_times(): + with pytest.raises(ValueError): + dt._validate_times(24, 0, 0) + with pytest.raises(ValueError): + dt._validate_times(0, 60, 0) + with pytest.raises(ValueError): + dt._validate_times(0, 0, 60) + + +def test_validate_dates(): + with pytest.raises(ValueError): + dt._validate_dates(1999, 1, 1) # year to small + with pytest.raises(ValueError): + dt._validate_dates(2100, 1, 1) # year too big + with pytest.raises(ValueError): + dt._validate_dates(2000, 0, 1) # month too small + with pytest.raises(ValueError): + dt._validate_dates(2000, 13, 1) # month too large + with pytest.raises(ValueError): + dt._validate_dates(2000, 4, 31) # day too big + with pytest.raises(ValueError): + dt._validate_dates(2001, 2, 29) # Not a leap year + + +def test_time(): + t = dt.time(12, 20, 14) + assert t.hour == 12 + assert t.minute == 20 + assert t.second == 14 + assert str(t) == "12:20:14" + + +def test_date(): + d = dt.date(2002, 11, 14) + assert d.year == 2002 + assert d.month == 11 + assert d.day == 14 + assert str(d) == "2002-11-14" + + +def test_datetime(): + dt1 = dt.datetime(2002, 11, 14, 12, 20, 14) + assert dt1.year == 2002 + assert dt1.month == 11 + assert dt1.day == 14 + assert dt1.hour == 12 + assert dt1.minute == 20 + assert dt1.second == 14 + assert str(dt1) == "2002-11-14 12:20:14" + + +def test_combine_and_split_datetime(): + t = dt.time(12, 20, 14) + d = dt.date(2002, 11, 14) + dt2 = dt.datetime.combine(d, t) + assert str(dt2) == "2002-11-14 12:20:14" + assert str(dt2.time()) == "12:20:14" + assert str(dt2.date()) == "2002-11-14" From 16443d6d81fade7e986f79986388c18f6a80fab8 Mon Sep 17 00:00:00 2001 From: "davitb2013@gmail.com" Date: Thu, 27 Feb 2025 21:24:07 -0800 Subject: [PATCH 14/16] one extra test for good measure --- tests/test_rtc_datetime.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/test_rtc_datetime.py b/tests/test_rtc_datetime.py index f90c2fa..59832eb 100644 --- a/tests/test_rtc_datetime.py +++ b/tests/test_rtc_datetime.py @@ -43,6 +43,10 @@ def test_validate_dates(): dt._validate_dates(2000, 4, 31) # day too big with pytest.raises(ValueError): dt._validate_dates(2001, 2, 29) # Not a leap year + try: + dt._validate_dates(2000, 2, 29) # Valid leap year date + except ValueError: + pytest.fail("Unexpected ValueError raised") def test_time(): From 9689d61f5c64cabe02054f6ba3be2cf2add2d336 Mon Sep 17 00:00:00 2001 From: "davitb2013@gmail.com" Date: Thu, 27 Feb 2025 21:37:00 -0800 Subject: [PATCH 15/16] remove unneeded dependancy --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 2515eb0..be1f5d4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,6 @@ dependencies = [ "coverage==7.6.10", "pre-commit==4.0.1", "pytest==8.3.2", - "adafruit-circuitpython-datetime==1.4.0" ] [tool.ruff.format] From e71ccf3497166cf7be954313f3a6565611705655 Mon Sep 17 00:00:00 2001 From: "davitb2013@gmail.com" Date: Thu, 27 Feb 2025 21:37:22 -0800 Subject: [PATCH 16/16] fix --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index be1f5d4..91b1054 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ requires-python = ">=3.12.3" dependencies = [ "coverage==7.6.10", "pre-commit==4.0.1", - "pytest==8.3.2", + "pytest==8.3.2" ] [tool.ruff.format]