mirror of
https://github.com/home-assistant/core.git
synced 2025-04-24 01:08:12 +00:00
Complete mysensors sensor coverage (#54471)
This commit is contained in:
parent
1e14b3a0ac
commit
028a3d3e53
@ -666,7 +666,6 @@ omit =
|
||||
homeassistant/components/mysensors/helpers.py
|
||||
homeassistant/components/mysensors/light.py
|
||||
homeassistant/components/mysensors/notify.py
|
||||
homeassistant/components/mysensors/sensor.py
|
||||
homeassistant/components/mysensors/switch.py
|
||||
homeassistant/components/mystrom/binary_sensor.py
|
||||
homeassistant/components/mystrom/light.py
|
||||
|
@ -3,13 +3,14 @@ from __future__ import annotations
|
||||
|
||||
from collections.abc import AsyncGenerator, Generator
|
||||
import json
|
||||
from typing import Any
|
||||
from typing import Any, Callable
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from mysensors.persistence import MySensorsJSONDecoder
|
||||
from mysensors.sensor import Sensor
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.device_tracker.legacy import Device
|
||||
from homeassistant.components.mqtt import DOMAIN as MQTT_DOMAIN
|
||||
from homeassistant.components.mysensors import CONF_VERSION, DEFAULT_BAUD_RATE
|
||||
from homeassistant.components.mysensors.const import (
|
||||
@ -27,14 +28,14 @@ from tests.common import MockConfigEntry, load_fixture
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def device_tracker_storage(mock_device_tracker_conf):
|
||||
def device_tracker_storage(mock_device_tracker_conf: list[Device]) -> list[Device]:
|
||||
"""Mock out device tracker known devices storage."""
|
||||
devices = mock_device_tracker_conf
|
||||
return devices
|
||||
|
||||
|
||||
@pytest.fixture(name="mqtt")
|
||||
def mock_mqtt_fixture(hass) -> None:
|
||||
def mock_mqtt_fixture(hass: HomeAssistant) -> None:
|
||||
"""Mock the MQTT integration."""
|
||||
hass.config.components.add(MQTT_DOMAIN)
|
||||
|
||||
@ -75,14 +76,14 @@ def mock_gateway_features(
|
||||
) -> None:
|
||||
"""Mock the gateway features."""
|
||||
|
||||
async def mock_start_persistence():
|
||||
async def mock_start_persistence() -> None:
|
||||
"""Load nodes from via persistence."""
|
||||
gateway = transport_class.call_args[0][0]
|
||||
gateway.sensors.update(nodes)
|
||||
|
||||
tasks.start_persistence.side_effect = mock_start_persistence
|
||||
|
||||
async def mock_start():
|
||||
async def mock_start() -> None:
|
||||
"""Mock the start method."""
|
||||
gateway = transport_class.call_args[0][0]
|
||||
gateway.on_conn_made(gateway)
|
||||
@ -97,7 +98,7 @@ def transport_fixture(serial_transport: MagicMock) -> MagicMock:
|
||||
|
||||
|
||||
@pytest.fixture(name="serial_entry")
|
||||
async def serial_entry_fixture(hass) -> MockConfigEntry:
|
||||
async def serial_entry_fixture(hass: HomeAssistant) -> MockConfigEntry:
|
||||
"""Create a config entry for a serial gateway."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
@ -120,15 +121,25 @@ def config_entry_fixture(serial_entry: MockConfigEntry) -> MockConfigEntry:
|
||||
@pytest.fixture
|
||||
async def integration(
|
||||
hass: HomeAssistant, transport: MagicMock, config_entry: MockConfigEntry
|
||||
) -> AsyncGenerator[MockConfigEntry, None]:
|
||||
) -> AsyncGenerator[tuple[MockConfigEntry, Callable[[str], None]], None]:
|
||||
"""Set up the mysensors integration with a config entry."""
|
||||
device = config_entry.data[CONF_DEVICE]
|
||||
config: dict[str, Any] = {DOMAIN: {CONF_GATEWAYS: [{CONF_DEVICE: device}]}}
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
def receive_message(message_string: str) -> None:
|
||||
"""Receive a message with the transport.
|
||||
|
||||
The message_string parameter is a string in the MySensors message format.
|
||||
"""
|
||||
gateway = transport.call_args[0][0]
|
||||
# node_id;child_id;command;ack;type;payload\n
|
||||
gateway.logic(message_string)
|
||||
|
||||
with patch("homeassistant.components.mysensors.device.UPDATE_DELAY", new=0):
|
||||
await async_setup_component(hass, DOMAIN, config)
|
||||
await hass.async_block_till_done()
|
||||
yield config_entry
|
||||
yield config_entry, receive_message
|
||||
|
||||
|
||||
def load_nodes_state(fixture_path: str) -> dict:
|
||||
@ -151,7 +162,7 @@ def gps_sensor_state_fixture() -> dict:
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def gps_sensor(gateway_nodes, gps_sensor_state) -> Sensor:
|
||||
def gps_sensor(gateway_nodes: dict[int, Sensor], gps_sensor_state: dict) -> Sensor:
|
||||
"""Load the gps sensor."""
|
||||
nodes = update_gateway_nodes(gateway_nodes, gps_sensor_state)
|
||||
node = nodes[1]
|
||||
@ -165,8 +176,70 @@ def power_sensor_state_fixture() -> dict:
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def power_sensor(gateway_nodes, power_sensor_state) -> Sensor:
|
||||
def power_sensor(gateway_nodes: dict[int, Sensor], power_sensor_state: dict) -> Sensor:
|
||||
"""Load the power sensor."""
|
||||
nodes = update_gateway_nodes(gateway_nodes, power_sensor_state)
|
||||
node = nodes[1]
|
||||
return node
|
||||
|
||||
|
||||
@pytest.fixture(name="energy_sensor_state", scope="session")
|
||||
def energy_sensor_state_fixture() -> dict:
|
||||
"""Load the energy sensor state."""
|
||||
return load_nodes_state("mysensors/energy_sensor_state.json")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def energy_sensor(
|
||||
gateway_nodes: dict[int, Sensor], energy_sensor_state: dict
|
||||
) -> Sensor:
|
||||
"""Load the energy sensor."""
|
||||
nodes = update_gateway_nodes(gateway_nodes, energy_sensor_state)
|
||||
node = nodes[1]
|
||||
return node
|
||||
|
||||
|
||||
@pytest.fixture(name="sound_sensor_state", scope="session")
|
||||
def sound_sensor_state_fixture() -> dict:
|
||||
"""Load the sound sensor state."""
|
||||
return load_nodes_state("mysensors/sound_sensor_state.json")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sound_sensor(gateway_nodes: dict[int, Sensor], sound_sensor_state: dict) -> Sensor:
|
||||
"""Load the sound sensor."""
|
||||
nodes = update_gateway_nodes(gateway_nodes, sound_sensor_state)
|
||||
node = nodes[1]
|
||||
return node
|
||||
|
||||
|
||||
@pytest.fixture(name="distance_sensor_state", scope="session")
|
||||
def distance_sensor_state_fixture() -> dict:
|
||||
"""Load the distance sensor state."""
|
||||
return load_nodes_state("mysensors/distance_sensor_state.json")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def distance_sensor(
|
||||
gateway_nodes: dict[int, Sensor], distance_sensor_state: dict
|
||||
) -> Sensor:
|
||||
"""Load the distance sensor."""
|
||||
nodes = update_gateway_nodes(gateway_nodes, distance_sensor_state)
|
||||
node = nodes[1]
|
||||
return node
|
||||
|
||||
|
||||
@pytest.fixture(name="temperature_sensor_state", scope="session")
|
||||
def temperature_sensor_state_fixture() -> dict:
|
||||
"""Load the temperature sensor state."""
|
||||
return load_nodes_state("mysensors/temperature_sensor_state.json")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def temperature_sensor(
|
||||
gateway_nodes: dict[int, Sensor], temperature_sensor_state: dict
|
||||
) -> Sensor:
|
||||
"""Load the temperature sensor."""
|
||||
nodes = update_gateway_nodes(gateway_nodes, temperature_sensor_state)
|
||||
node = nodes[1]
|
||||
return node
|
||||
|
@ -1,31 +1,161 @@
|
||||
"""Provide tests for mysensors sensor platform."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Callable
|
||||
|
||||
from homeassistant.components.sensor import ATTR_STATE_CLASS, STATE_CLASS_MEASUREMENT
|
||||
from mysensors.sensor import Sensor
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
ATTR_LAST_RESET,
|
||||
ATTR_STATE_CLASS,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
ATTR_DEVICE_CLASS,
|
||||
ATTR_ICON,
|
||||
ATTR_UNIT_OF_MEASUREMENT,
|
||||
DEVICE_CLASS_ENERGY,
|
||||
DEVICE_CLASS_POWER,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
ENERGY_KILO_WATT_HOUR,
|
||||
POWER_WATT,
|
||||
TEMP_CELSIUS,
|
||||
TEMP_FAHRENHEIT,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.util.dt import utc_from_timestamp
|
||||
from homeassistant.util.unit_system import IMPERIAL_SYSTEM, METRIC_SYSTEM, UnitSystem
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
async def test_gps_sensor(hass, gps_sensor, integration):
|
||||
async def test_gps_sensor(
|
||||
hass: HomeAssistant,
|
||||
gps_sensor: Sensor,
|
||||
integration: tuple[MockConfigEntry, Callable[[str], None]],
|
||||
) -> None:
|
||||
"""Test a gps sensor."""
|
||||
entity_id = "sensor.gps_sensor_1_1"
|
||||
_, receive_message = integration
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
|
||||
assert state
|
||||
assert state.state == "40.741894,-73.989311,12"
|
||||
|
||||
altitude = 0
|
||||
new_coords = "40.782,-73.965"
|
||||
message_string = f"1;1;1;0;49;{new_coords},{altitude}\n"
|
||||
|
||||
async def test_power_sensor(hass, power_sensor, integration):
|
||||
receive_message(message_string)
|
||||
# the integration adds multiple jobs to do the update currently
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
|
||||
assert state
|
||||
assert state.state == f"{new_coords},{altitude}"
|
||||
|
||||
|
||||
async def test_power_sensor(
|
||||
hass: HomeAssistant,
|
||||
power_sensor: Sensor,
|
||||
integration: tuple[MockConfigEntry, Callable[[str], None]],
|
||||
) -> None:
|
||||
"""Test a power sensor."""
|
||||
entity_id = "sensor.power_sensor_1_1"
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
|
||||
assert state
|
||||
assert state.state == "1200"
|
||||
assert state.attributes[ATTR_DEVICE_CLASS] == DEVICE_CLASS_POWER
|
||||
assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == POWER_WATT
|
||||
assert state.attributes[ATTR_STATE_CLASS] == STATE_CLASS_MEASUREMENT
|
||||
assert ATTR_LAST_RESET not in state.attributes
|
||||
|
||||
|
||||
async def test_energy_sensor(
|
||||
hass: HomeAssistant,
|
||||
energy_sensor: Sensor,
|
||||
integration: tuple[MockConfigEntry, Callable[[str], None]],
|
||||
) -> None:
|
||||
"""Test an energy sensor."""
|
||||
entity_id = "sensor.energy_sensor_1_1"
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
|
||||
assert state
|
||||
assert state.state == "18000"
|
||||
assert state.attributes[ATTR_DEVICE_CLASS] == DEVICE_CLASS_ENERGY
|
||||
assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == ENERGY_KILO_WATT_HOUR
|
||||
assert state.attributes[ATTR_STATE_CLASS] == STATE_CLASS_MEASUREMENT
|
||||
assert state.attributes[ATTR_LAST_RESET] == utc_from_timestamp(0).isoformat()
|
||||
|
||||
|
||||
async def test_sound_sensor(
|
||||
hass: HomeAssistant,
|
||||
sound_sensor: Sensor,
|
||||
integration: tuple[MockConfigEntry, Callable[[str], None]],
|
||||
) -> None:
|
||||
"""Test a sound sensor."""
|
||||
entity_id = "sensor.sound_sensor_1_1"
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
|
||||
assert state
|
||||
assert state.state == "10"
|
||||
assert state.attributes[ATTR_ICON] == "mdi:volume-high"
|
||||
assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == "dB"
|
||||
|
||||
|
||||
async def test_distance_sensor(
|
||||
hass: HomeAssistant,
|
||||
distance_sensor: Sensor,
|
||||
integration: tuple[MockConfigEntry, Callable[[str], None]],
|
||||
) -> None:
|
||||
"""Test a distance sensor."""
|
||||
entity_id = "sensor.distance_sensor_1_1"
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
|
||||
assert state
|
||||
assert state.state == "15"
|
||||
assert state.attributes[ATTR_ICON] == "mdi:ruler"
|
||||
assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == "cm"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"unit_system, unit",
|
||||
[(METRIC_SYSTEM, TEMP_CELSIUS), (IMPERIAL_SYSTEM, TEMP_FAHRENHEIT)],
|
||||
)
|
||||
async def test_temperature_sensor(
|
||||
hass: HomeAssistant,
|
||||
temperature_sensor: Sensor,
|
||||
integration: tuple[MockConfigEntry, Callable[[str], None]],
|
||||
unit_system: UnitSystem,
|
||||
unit: str,
|
||||
) -> None:
|
||||
"""Test a temperature sensor."""
|
||||
entity_id = "sensor.temperature_sensor_1_1"
|
||||
hass.config.units = unit_system
|
||||
_, receive_message = integration
|
||||
temperature = "22.0"
|
||||
message_string = f"1;1;1;0;0;{temperature}\n"
|
||||
|
||||
receive_message(message_string)
|
||||
# the integration adds multiple jobs to do the update currently
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
|
||||
assert state
|
||||
assert state.state == temperature
|
||||
assert state.attributes[ATTR_DEVICE_CLASS] == DEVICE_CLASS_TEMPERATURE
|
||||
assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == unit
|
||||
assert state.attributes[ATTR_STATE_CLASS] == STATE_CLASS_MEASUREMENT
|
||||
|
22
tests/fixtures/mysensors/distance_sensor_state.json
vendored
Normal file
22
tests/fixtures/mysensors/distance_sensor_state.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"1": {
|
||||
"sensor_id": 1,
|
||||
"children": {
|
||||
"1": {
|
||||
"id": 1,
|
||||
"type": 15,
|
||||
"description": "",
|
||||
"values": {
|
||||
"13": "15",
|
||||
"43": "cm"
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": 17,
|
||||
"sketch_name": "Distance Sensor",
|
||||
"sketch_version": "1.0",
|
||||
"battery_level": 0,
|
||||
"protocol_version": "2.3.2",
|
||||
"heartbeat": 0
|
||||
}
|
||||
}
|
21
tests/fixtures/mysensors/energy_sensor_state.json
vendored
Normal file
21
tests/fixtures/mysensors/energy_sensor_state.json
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"1": {
|
||||
"sensor_id": 1,
|
||||
"children": {
|
||||
"1": {
|
||||
"id": 1,
|
||||
"type": 13,
|
||||
"description": "",
|
||||
"values": {
|
||||
"18": "18000"
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": 17,
|
||||
"sketch_name": "Energy Sensor",
|
||||
"sketch_version": "1.0",
|
||||
"battery_level": 0,
|
||||
"protocol_version": "2.3.2",
|
||||
"heartbeat": 0
|
||||
}
|
||||
}
|
21
tests/fixtures/mysensors/sound_sensor_state.json
vendored
Normal file
21
tests/fixtures/mysensors/sound_sensor_state.json
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"1": {
|
||||
"sensor_id": 1,
|
||||
"children": {
|
||||
"1": {
|
||||
"id": 1,
|
||||
"type": 33,
|
||||
"description": "",
|
||||
"values": {
|
||||
"37": "10"
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": 17,
|
||||
"sketch_name": "Sound Sensor",
|
||||
"sketch_version": "1.0",
|
||||
"battery_level": 0,
|
||||
"protocol_version": "2.3.2",
|
||||
"heartbeat": 0
|
||||
}
|
||||
}
|
21
tests/fixtures/mysensors/temperature_sensor_state.json
vendored
Normal file
21
tests/fixtures/mysensors/temperature_sensor_state.json
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"1": {
|
||||
"sensor_id": 1,
|
||||
"children": {
|
||||
"1": {
|
||||
"id": 1,
|
||||
"type": 6,
|
||||
"description": "",
|
||||
"values": {
|
||||
"0": "20.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": 17,
|
||||
"sketch_name": "Temperature Sensor",
|
||||
"sketch_version": "1.0",
|
||||
"battery_level": 0,
|
||||
"protocol_version": "2.3.2",
|
||||
"heartbeat": 0
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user