UniFi has changed to not report uptime in epoch form (#47492)

This commit is contained in:
Robert Svensson 2021-03-12 20:55:11 +01:00 committed by GitHub
parent 9a98dcf432
commit 597bf67f5a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 199 additions and 148 deletions

View file

@ -3,6 +3,9 @@
Support for bandwidth sensors of network clients. Support for bandwidth sensors of network clients.
Support for uptime sensors of network clients. Support for uptime sensors of network clients.
""" """
from datetime import datetime, timedelta
from homeassistant.components.sensor import DEVICE_CLASS_TIMESTAMP, DOMAIN from homeassistant.components.sensor import DEVICE_CLASS_TIMESTAMP, DOMAIN
from homeassistant.const import DATA_MEGABYTES from homeassistant.const import DATA_MEGABYTES
from homeassistant.core import callback from homeassistant.core import callback
@ -140,8 +143,10 @@ class UniFiUpTimeSensor(UniFiClient):
return f"{super().name} {self.TYPE.capitalize()}" return f"{super().name} {self.TYPE.capitalize()}"
@property @property
def state(self) -> int: def state(self) -> datetime:
"""Return the uptime of the client.""" """Return the uptime of the client."""
if self.client.uptime < 1000000000:
return (dt_util.now() - timedelta(seconds=self.client.uptime)).isoformat()
return dt_util.utc_from_timestamp(float(self.client.uptime)).isoformat() return dt_util.utc_from_timestamp(float(self.client.uptime)).isoformat()
async def options_updated(self) -> None: async def options_updated(self) -> None:

View file

@ -1,5 +1,7 @@
"""UniFi sensor platform tests.""" """UniFi sensor platform tests."""
from copy import deepcopy
from datetime import datetime
from unittest.mock import patch
from aiounifi.controller import MESSAGE_CLIENT, MESSAGE_CLIENT_REMOVED from aiounifi.controller import MESSAGE_CLIENT, MESSAGE_CLIENT_REMOVED
@ -13,40 +15,10 @@ from homeassistant.components.unifi.const import (
DOMAIN as UNIFI_DOMAIN, DOMAIN as UNIFI_DOMAIN,
) )
from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.dispatcher import async_dispatcher_send
import homeassistant.util.dt as dt_util
from .test_controller import setup_unifi_integration from .test_controller import setup_unifi_integration
CLIENTS = [
{
"hostname": "Wired client hostname",
"ip": "10.0.0.1",
"is_wired": True,
"last_seen": 1562600145,
"mac": "00:00:00:00:00:01",
"name": "Wired client name",
"oui": "Producer",
"sw_mac": "00:00:00:00:01:01",
"sw_port": 1,
"wired-rx_bytes": 1234000000,
"wired-tx_bytes": 5678000000,
"uptime": 1600094505,
},
{
"hostname": "Wireless client hostname",
"ip": "10.0.0.2",
"is_wired": False,
"last_seen": 1562600145,
"mac": "00:00:00:00:00:02",
"name": "Wireless client name",
"oui": "Producer",
"sw_mac": "00:00:00:00:01:01",
"sw_port": 2,
"rx_bytes": 1234000000,
"tx_bytes": 5678000000,
"uptime": 1600094505,
},
]
async def test_no_clients(hass, aioclient_mock): async def test_no_clients(hass, aioclient_mock):
"""Test the update_clients function when no clients are found.""" """Test the update_clients function when no clients are found."""
@ -62,112 +34,93 @@ async def test_no_clients(hass, aioclient_mock):
assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 0 assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 0
async def test_sensors(hass, aioclient_mock, mock_unifi_websocket): async def test_bandwidth_sensors(hass, aioclient_mock, mock_unifi_websocket):
"""Test the update_items function with some clients.""" """Verify that bandwidth sensors are working as expected."""
wired_client = {
"hostname": "Wired client",
"is_wired": True,
"mac": "00:00:00:00:00:01",
"oui": "Producer",
"wired-rx_bytes": 1234000000,
"wired-tx_bytes": 5678000000,
}
wireless_client = {
"is_wired": False,
"mac": "00:00:00:00:00:02",
"name": "Wireless client",
"oui": "Producer",
"rx_bytes": 2345000000,
"tx_bytes": 6789000000,
}
options = {
CONF_ALLOW_BANDWIDTH_SENSORS: True,
CONF_ALLOW_UPTIME_SENSORS: False,
CONF_TRACK_CLIENTS: False,
CONF_TRACK_DEVICES: False,
}
config_entry = await setup_unifi_integration( config_entry = await setup_unifi_integration(
hass, hass,
aioclient_mock, aioclient_mock,
options={ options=options,
CONF_ALLOW_BANDWIDTH_SENSORS: True, clients_response=[wired_client, wireless_client],
CONF_ALLOW_UPTIME_SENSORS: True,
CONF_TRACK_CLIENTS: False,
CONF_TRACK_DEVICES: False,
},
clients_response=CLIENTS,
) )
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 6 assert len(hass.states.async_all()) == 5
assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 4
assert hass.states.get("sensor.wired_client_rx").state == "1234.0"
assert hass.states.get("sensor.wired_client_tx").state == "5678.0"
assert hass.states.get("sensor.wireless_client_rx").state == "2345.0"
assert hass.states.get("sensor.wireless_client_tx").state == "6789.0"
wired_client_rx = hass.states.get("sensor.wired_client_name_rx") # Verify state update
assert wired_client_rx.state == "1234.0"
wired_client_tx = hass.states.get("sensor.wired_client_name_tx") wireless_client["rx_bytes"] = 3456000000
assert wired_client_tx.state == "5678.0" wireless_client["tx_bytes"] = 7891000000
wired_client_uptime = hass.states.get("sensor.wired_client_name_uptime")
assert wired_client_uptime.state == "2020-09-14T14:41:45+00:00"
wireless_client_rx = hass.states.get("sensor.wireless_client_name_rx")
assert wireless_client_rx.state == "1234.0"
wireless_client_tx = hass.states.get("sensor.wireless_client_name_tx")
assert wireless_client_tx.state == "5678.0"
wireless_client_uptime = hass.states.get("sensor.wireless_client_name_uptime")
assert wireless_client_uptime.state == "2020-09-14T14:41:45+00:00"
clients = deepcopy(CLIENTS)
clients[0]["is_wired"] = False
clients[1]["rx_bytes"] = 2345000000
clients[1]["tx_bytes"] = 6789000000
clients[1]["uptime"] = 1600180860
mock_unifi_websocket( mock_unifi_websocket(
data={ data={
"meta": {"message": MESSAGE_CLIENT}, "meta": {"message": MESSAGE_CLIENT},
"data": clients, "data": [wireless_client],
} }
) )
await hass.async_block_till_done() await hass.async_block_till_done()
wireless_client_rx = hass.states.get("sensor.wireless_client_name_rx") assert hass.states.get("sensor.wireless_client_rx").state == "3456.0"
assert wireless_client_rx.state == "2345.0" assert hass.states.get("sensor.wireless_client_tx").state == "7891.0"
wireless_client_tx = hass.states.get("sensor.wireless_client_name_tx") # Disable option
assert wireless_client_tx.state == "6789.0"
wireless_client_uptime = hass.states.get("sensor.wireless_client_name_uptime") options[CONF_ALLOW_BANDWIDTH_SENSORS] = False
assert wireless_client_uptime.state == "2020-09-15T14:41:00+00:00" hass.config_entries.async_update_entry(config_entry, options=options.copy())
hass.config_entries.async_update_entry(
config_entry,
options={
CONF_ALLOW_BANDWIDTH_SENSORS: False,
CONF_ALLOW_UPTIME_SENSORS: False,
},
)
await hass.async_block_till_done() await hass.async_block_till_done()
wireless_client_rx = hass.states.get("sensor.wireless_client_name_rx") assert len(hass.states.async_all()) == 1
assert wireless_client_rx is None assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 0
assert hass.states.get("sensor.wireless_client_rx") is None
assert hass.states.get("sensor.wireless_client_tx") is None
assert hass.states.get("sensor.wired_client_rx") is None
assert hass.states.get("sensor.wired_client_tx") is None
wireless_client_tx = hass.states.get("sensor.wireless_client_name_tx") # Enable option
assert wireless_client_tx is None
wired_client_uptime = hass.states.get("sensor.wired_client_name_uptime") options[CONF_ALLOW_BANDWIDTH_SENSORS] = True
assert wired_client_uptime is None hass.config_entries.async_update_entry(config_entry, options=options.copy())
wireless_client_uptime = hass.states.get("sensor.wireless_client_name_uptime")
assert wireless_client_uptime is None
hass.config_entries.async_update_entry(
config_entry,
options={
CONF_ALLOW_BANDWIDTH_SENSORS: True,
CONF_ALLOW_UPTIME_SENSORS: True,
},
)
await hass.async_block_till_done() await hass.async_block_till_done()
wireless_client_rx = hass.states.get("sensor.wireless_client_name_rx") assert len(hass.states.async_all()) == 5
assert wireless_client_rx.state == "2345.0" assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 4
assert hass.states.get("sensor.wireless_client_rx")
wireless_client_tx = hass.states.get("sensor.wireless_client_name_tx") assert hass.states.get("sensor.wireless_client_tx")
assert wireless_client_tx.state == "6789.0" assert hass.states.get("sensor.wired_client_rx")
assert hass.states.get("sensor.wired_client_tx")
wireless_client_uptime = hass.states.get("sensor.wireless_client_name_uptime")
assert wireless_client_uptime.state == "2020-09-15T14:41:00+00:00"
wired_client_uptime = hass.states.get("sensor.wired_client_name_uptime")
assert wired_client_uptime.state == "2020-09-14T14:41:45+00:00"
# Try to add the sensors again, using a signal # Try to add the sensors again, using a signal
clients_connected = set()
clients_connected = {wired_client["mac"], wireless_client["mac"]}
devices_connected = set() devices_connected = set()
clients_connected.add(clients[0]["mac"]) controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
clients_connected.add(clients[1]["mac"])
async_dispatcher_send( async_dispatcher_send(
hass, hass,
@ -175,14 +128,123 @@ async def test_sensors(hass, aioclient_mock, mock_unifi_websocket):
clients_connected, clients_connected,
devices_connected, devices_connected,
) )
await hass.async_block_till_done() await hass.async_block_till_done()
assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 6 assert len(hass.states.async_all()) == 5
assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 4
async def test_uptime_sensors(hass, aioclient_mock, mock_unifi_websocket):
"""Verify that uptime sensors are working as expected."""
client1 = {
"mac": "00:00:00:00:00:01",
"name": "client1",
"oui": "Producer",
"uptime": 1609506061,
}
client2 = {
"hostname": "Client2",
"mac": "00:00:00:00:00:02",
"oui": "Producer",
"uptime": 60,
}
options = {
CONF_ALLOW_BANDWIDTH_SENSORS: False,
CONF_ALLOW_UPTIME_SENSORS: True,
CONF_TRACK_CLIENTS: False,
CONF_TRACK_DEVICES: False,
}
now = datetime(2021, 1, 1, 1, tzinfo=dt_util.UTC)
with patch("homeassistant.util.dt.now", return_value=now):
config_entry = await setup_unifi_integration(
hass,
aioclient_mock,
options=options,
clients_response=[client1, client2],
)
assert len(hass.states.async_all()) == 3
assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 2
assert hass.states.get("sensor.client1_uptime").state == "2021-01-01T13:01:01+00:00"
assert hass.states.get("sensor.client2_uptime").state == "2021-01-01T00:59:00+00:00"
# Verify state update
client1["uptime"] = 1609506062
mock_unifi_websocket(
data={
"meta": {"message": MESSAGE_CLIENT},
"data": [client1],
}
)
await hass.async_block_till_done()
assert hass.states.get("sensor.client1_uptime").state == "2021-01-01T13:01:02+00:00"
# Disable option
options[CONF_ALLOW_UPTIME_SENSORS] = False
hass.config_entries.async_update_entry(config_entry, options=options.copy())
await hass.async_block_till_done()
assert len(hass.states.async_all()) == 1
assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 0
assert hass.states.get("sensor.client1_uptime") is None
assert hass.states.get("sensor.client2_uptime") is None
# Enable option
options[CONF_ALLOW_UPTIME_SENSORS] = True
with patch("homeassistant.util.dt.now", return_value=now):
hass.config_entries.async_update_entry(config_entry, options=options.copy())
await hass.async_block_till_done()
assert len(hass.states.async_all()) == 3
assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 2
assert hass.states.get("sensor.client1_uptime")
assert hass.states.get("sensor.client2_uptime")
# Try to add the sensors again, using a signal
clients_connected = {client1["mac"], client2["mac"]}
devices_connected = set()
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
async_dispatcher_send(
hass,
controller.signal_update,
clients_connected,
devices_connected,
)
await hass.async_block_till_done()
assert len(hass.states.async_all()) == 3
assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 2
async def test_remove_sensors(hass, aioclient_mock, mock_unifi_websocket): async def test_remove_sensors(hass, aioclient_mock, mock_unifi_websocket):
"""Test the remove_items function with some clients.""" """Verify removing of clients work as expected."""
wired_client = {
"hostname": "Wired client",
"is_wired": True,
"mac": "00:00:00:00:00:01",
"oui": "Producer",
"wired-rx_bytes": 1234000000,
"wired-tx_bytes": 5678000000,
"uptime": 1600094505,
}
wireless_client = {
"is_wired": False,
"mac": "00:00:00:00:00:02",
"name": "Wireless client",
"oui": "Producer",
"rx_bytes": 2345000000,
"tx_bytes": 6789000000,
"uptime": 60,
}
await setup_unifi_integration( await setup_unifi_integration(
hass, hass,
aioclient_mock, aioclient_mock,
@ -190,51 +252,35 @@ async def test_remove_sensors(hass, aioclient_mock, mock_unifi_websocket):
CONF_ALLOW_BANDWIDTH_SENSORS: True, CONF_ALLOW_BANDWIDTH_SENSORS: True,
CONF_ALLOW_UPTIME_SENSORS: True, CONF_ALLOW_UPTIME_SENSORS: True,
}, },
clients_response=CLIENTS, clients_response=[wired_client, wireless_client],
) )
assert len(hass.states.async_all()) == 9
assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 6 assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 6
assert len(hass.states.async_entity_ids(TRACKER_DOMAIN)) == 2 assert len(hass.states.async_entity_ids(TRACKER_DOMAIN)) == 2
assert hass.states.get("sensor.wired_client_rx")
assert hass.states.get("sensor.wired_client_tx")
assert hass.states.get("sensor.wired_client_uptime")
assert hass.states.get("sensor.wireless_client_rx")
assert hass.states.get("sensor.wireless_client_tx")
assert hass.states.get("sensor.wireless_client_uptime")
wired_client_rx = hass.states.get("sensor.wired_client_name_rx") # Remove wired client
assert wired_client_rx is not None
wired_client_tx = hass.states.get("sensor.wired_client_name_tx")
assert wired_client_tx is not None
wired_client_uptime = hass.states.get("sensor.wired_client_name_uptime")
assert wired_client_uptime is not None
wireless_client_rx = hass.states.get("sensor.wireless_client_name_rx")
assert wireless_client_rx is not None
wireless_client_tx = hass.states.get("sensor.wireless_client_name_tx")
assert wireless_client_tx is not None
wireless_client_uptime = hass.states.get("sensor.wireless_client_name_uptime")
assert wireless_client_uptime is not None
mock_unifi_websocket( mock_unifi_websocket(
data={ data={
"meta": {"message": MESSAGE_CLIENT_REMOVED}, "meta": {"message": MESSAGE_CLIENT_REMOVED},
"data": [CLIENTS[0]], "data": [wired_client],
} }
) )
await hass.async_block_till_done() await hass.async_block_till_done()
assert len(hass.states.async_all()) == 5
assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 3 assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 3
assert len(hass.states.async_entity_ids(TRACKER_DOMAIN)) == 1 assert len(hass.states.async_entity_ids(TRACKER_DOMAIN)) == 1
assert hass.states.get("sensor.wired_client_rx") is None
wired_client_rx = hass.states.get("sensor.wired_client_name_rx") assert hass.states.get("sensor.wired_client_tx") is None
assert wired_client_rx is None assert hass.states.get("sensor.wired_client_uptime") is None
wired_client_tx = hass.states.get("sensor.wired_client_name_tx") assert hass.states.get("sensor.wireless_client_rx")
assert wired_client_tx is None assert hass.states.get("sensor.wireless_client_tx")
assert hass.states.get("sensor.wireless_client_uptime")
wired_client_uptime = hass.states.get("sensor.wired_client_name_uptime")
assert wired_client_uptime is None
wireless_client_rx = hass.states.get("sensor.wireless_client_name_rx")
assert wireless_client_rx is not None
wireless_client_tx = hass.states.get("sensor.wireless_client_name_tx")
assert wireless_client_tx is not None
wireless_client_uptime = hass.states.get("sensor.wireless_client_name_uptime")
assert wireless_client_uptime is not None