Skip to content

Commit

Permalink
0.45.1 Release
Browse files Browse the repository at this point in the history
0.45.1 Release
  • Loading branch information
puddly committed Apr 27, 2022
2 parents 67a8dfa + 08ec0f6 commit e9d6adc
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 20 deletions.
55 changes: 49 additions & 6 deletions tests/test_appdb.py
@@ -1,5 +1,4 @@
import asyncio
from datetime import datetime
import os
import sqlite3
import sys
Expand Down Expand Up @@ -178,8 +177,8 @@ async def test_database(tmpdir):
ts = time.time()
dev.last_seen = ts
dev_last_seen = dev.last_seen
assert isinstance(dev.last_seen, datetime)
assert abs(dev.last_seen.timestamp() - ts) < 0.1
assert isinstance(dev.last_seen, float)
assert abs(dev.last_seen - ts) < 0.01

# Test a CustomDevice
custom_ieee = make_ieee(1)
Expand All @@ -202,7 +201,7 @@ async def test_database(tmpdir):
assert dev.endpoints[1].in_clusters[0x0008]._attr_cache[0x0011] == 17
assert dev.endpoints[99].in_clusters[0x0008]._attr_cache[0x0011] == 17
custom_dev_last_seen = dev.last_seen
assert isinstance(custom_dev_last_seen, datetime)
assert isinstance(custom_dev_last_seen, float)

await app.pre_shutdown()

Expand All @@ -221,15 +220,15 @@ async def test_database(tmpdir):
assert dev.endpoints[3].device_type == profiles.zll.DeviceType.COLOR_LIGHT
assert dev.relays == relays_1
# The timestamp won't be restored exactly but it is more than close enough
assert abs((dev.last_seen - dev_last_seen).total_seconds()) < 0.01
assert abs(dev.last_seen - dev_last_seen) < 0.01

dev = app2.get_device(custom_ieee)
# This virtual attribute is added by the quirk, there is no corresponding cluster
# stored in the database, nor is there a corresponding endpoint 99
assert dev.endpoints[1].in_clusters[0x0008]._attr_cache[0x0011] == 17
assert dev.endpoints[99].in_clusters[0x0008]._attr_cache[0x0011] == 17
assert dev.relays == relays_2
assert abs((dev.last_seen - custom_dev_last_seen).total_seconds()) < 0.01
assert abs(dev.last_seen - custom_dev_last_seen) < 0.01
dev.relays = None

app.handle_leave(99, ieee)
Expand Down Expand Up @@ -774,6 +773,50 @@ async def test_load_unsupp_attr_wrong_cluster(tmpdir):
await app.pre_shutdown()


async def test_last_seen(tmpdir):
db = os.path.join(str(tmpdir), "test.db")
app = await make_app(db)

ieee = make_ieee()
app.handle_join(99, ieee, 0)

dev = app.get_device(ieee=ieee)
ep = dev.add_endpoint(3)
ep.status = zigpy.endpoint.Status.ZDO_INIT
ep.profile_id = 260
ep.device_type = profiles.zha.DeviceType.PUMP
clus = ep.add_input_cluster(0)
ep.add_output_cluster(1)
clus._update_attribute(4, "Custom")
clus._update_attribute(5, "Model")
app.device_initialized(dev)

old_last_seen = dev.last_seen
await app.pre_shutdown()

# The `last_seen` of a joined device persists
app = await make_app(db)
dev = app.get_device(ieee=ieee)
await app.pre_shutdown()

next_last_seen = dev.last_seen
assert abs(next_last_seen - old_last_seen) < 0.01

await asyncio.sleep(0.1)

# Now the last_seen will update
app = await make_app(db)
dev = app.get_device(ieee=ieee)
dev.update_last_seen()
await app.pre_shutdown()

# And it will be updated when the database next loads
app = await make_app(db)
dev = app.get_device(ieee=ieee)
assert dev.last_seen > next_last_seen + 0.1
await app.pre_shutdown()


@pytest.mark.parametrize(
"stdlib_version,use_sqlite",
[
Expand Down
25 changes: 18 additions & 7 deletions tests/test_appdb_migration.py
Expand Up @@ -405,13 +405,6 @@ async def test_v4_to_v5_migration_bad_neighbors(test_db, with_bad_neighbor):
assert num_new_neighbors == num_v4_neighbors


async def test_v5_to_v6_migration(test_db):
test_db_v5 = test_db("simple_v5.sql")

app = await make_app(test_db_v5)
await app.pre_shutdown()


@pytest.mark.parametrize("with_quirk_attribute", [False, True])
async def test_v4_to_v6_migration_missing_endpoints(test_db, with_quirk_attribute):
"""V5's schema was too rigid and failed to migrate endpoints created by quirks"""
Expand Down Expand Up @@ -495,3 +488,21 @@ async def test_migration_missing_tables():
appdb.execute.assert_called_once_with("SELECT * FROM table2_v1")

await appdb.shutdown()


async def test_last_seen_migration(test_db):
test_db_v5 = test_db("simple_v5.sql")

# To preserve the old behavior, `0` will not be exposed to ZHA, only `None`
app = await make_app(test_db_v5)
dev = app.get_device(nwk=0xBD4D)

assert dev.last_seen is None
dev.update_last_seen()
assert isinstance(dev.last_seen, float)
await app.pre_shutdown()

# But the device's `last_seen` will still update properly when it's actually set
app = await make_app(test_db_v5)
assert isinstance(app.get_device(nwk=0xBD4D).last_seen, float)
await app.pre_shutdown()
2 changes: 1 addition & 1 deletion tests/test_device.py
Expand Up @@ -440,7 +440,7 @@ def test_device_last_seen(dev, monkeypatch):

dev.last_seen = 0
epoch = datetime(1970, 1, 1, 0, 0, 0, 0, tzinfo=timezone.utc)
assert dev.last_seen == epoch
assert dev.last_seen == epoch.timestamp()

dev.listener_event.assert_called_once_with("device_last_seen_updated", epoch)
dev.listener_event.reset_mock()
Expand Down
2 changes: 1 addition & 1 deletion zigpy/__init__.py
@@ -1,5 +1,5 @@
MAJOR_VERSION = 0
MINOR_VERSION = 45
PATCH_VERSION = "0"
PATCH_VERSION = "1"
__short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}"
__version__ = f"{__short_version__}.{PATCH_VERSION}"
8 changes: 5 additions & 3 deletions zigpy/appdb.py
Expand Up @@ -228,7 +228,7 @@ def device_last_seen_updated(

async def _save_device_last_seen(self, ieee: t.EUI64, last_seen: datetime) -> None:
await self.execute(
f"UPDATE devices{DB_V} SET last_seen=? WHERE ieee=?", (ieee, last_seen)
f"UPDATE devices{DB_V} SET last_seen=? WHERE ieee=?", (last_seen, ieee)
)
await self._db.commit()

Expand Down Expand Up @@ -372,7 +372,7 @@ async def _save_device(self, device: zigpy.typing.DeviceType) -> None:
status=excluded.status,
last_seen=excluded.last_seen"""
await self.execute(
q, (device.ieee, device.nwk, device.status, device.last_seen)
q, (device.ieee, device.nwk, device.status, device._last_seen or UNIX_EPOCH)
)

if device.node_desc is not None:
Expand Down Expand Up @@ -565,7 +565,9 @@ async def _load_devices(self) -> None:
async for (ieee, nwk, status, last_seen) in cursor:
dev = self._application.add_device(ieee, nwk)
dev.status = zigpy.device.Status(status)
dev._last_seen = last_seen

if last_seen > UNIX_EPOCH:
dev._last_seen = last_seen

async def _load_node_descriptors(self) -> None:
async with self.execute(f"SELECT * FROM node_descriptors{DB_V}") as cursor:
Expand Down
4 changes: 2 additions & 2 deletions zigpy/device.py
Expand Up @@ -85,8 +85,8 @@ def update_last_seen(self) -> None:
self.last_seen = datetime.now(timezone.utc)

@property
def last_seen(self) -> datetime | None:
return self._last_seen
def last_seen(self) -> float | None:
return self._last_seen.timestamp() if self._last_seen is not None else None

@last_seen.setter
def last_seen(self, value: datetime | int | float):
Expand Down

0 comments on commit e9d6adc

Please sign in to comment.