"""The tests for OctoPrint number module.""" from datetime import UTC, datetime from typing import Any from unittest.mock import patch import pytest from syrupy.assertion import SnapshotAssertion from homeassistant.components.number import ( ATTR_VALUE, DOMAIN as NUMBER_DOMAIN, SERVICE_SET_VALUE, ) from homeassistant.const import ATTR_ENTITY_ID, STATE_UNKNOWN, Platform from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er from tests.common import MockConfigEntry, snapshot_platform @pytest.fixture def platform() -> Platform: """Fixture to specify platform.""" return Platform.NUMBER @pytest.fixture def job() -> dict[str, Any]: """Job fixture.""" return __standard_job() @pytest.mark.parametrize( "printer", [ { "state": { "flags": {"printing": True}, "text": "Operational", }, "temperature": { "tool0": {"actual": 18.83136, "target": 37.83136}, "tool1": {"actual": 21.0, "target": 31.0}, "bed": {"actual": 25.5, "target": 60.0}, }, }, ], ) @pytest.mark.freeze_time(datetime(2020, 2, 20, 9, 10, 13, 543, tzinfo=UTC)) async def test_numbers( hass: HomeAssistant, entity_registry: er.EntityRegistry, snapshot: SnapshotAssertion, init_integration: MockConfigEntry, ) -> None: """Test the underlying number entities.""" await snapshot_platform(hass, entity_registry, snapshot, init_integration.entry_id) @pytest.mark.parametrize( "printer", [ { "state": { "flags": {"printing": True, "paused": False}, "text": "Operational", }, "temperature": { "tool0": {"actual": 18.83136, "target": None}, "bed": {"actual": 25.5, "target": None}, }, }, ], ) @pytest.mark.freeze_time(datetime(2020, 2, 20, 9, 10, 0)) @pytest.mark.usefixtures("init_integration") async def test_numbers_no_target_temp( hass: HomeAssistant, entity_registry: er.EntityRegistry, ) -> None: """Test the number entities when target temperature is None.""" state = hass.states.get("number.octoprint_extruder_temperature") assert state is not None assert state.state == STATE_UNKNOWN assert state.name == "OctoPrint Extruder temperature" entry = entity_registry.async_get("number.octoprint_extruder_temperature") assert entry.unique_id == "uuid_tool0_temperature" state = hass.states.get("number.octoprint_bed_temperature") assert state is not None assert state.state == STATE_UNKNOWN assert state.name == "OctoPrint Bed temperature" entry = entity_registry.async_get("number.octoprint_bed_temperature") assert entry.unique_id == "uuid_bed_temperature" @pytest.mark.parametrize( "printer", [ { "state": { "flags": {"printing": False}, "text": "Operational", }, "temperature": {"tool0": {"actual": 18.83136, "target": 25.0}}, }, ], ) @pytest.mark.freeze_time(datetime(2020, 2, 20, 9, 10, 0)) @pytest.mark.usefixtures("init_integration") async def test_set_tool_temp( hass: HomeAssistant, ) -> None: """Test setting tool temperature via number entity.""" with patch( "pyoctoprintapi.OctoprintClient.set_tool_temperature" ) as mock_set_tool_temp: entity_component = hass.data[NUMBER_DOMAIN] entity = entity_component.get_entity("number.octoprint_extruder_temperature") assert entity is not None await hass.services.async_call( NUMBER_DOMAIN, SERVICE_SET_VALUE, {ATTR_ENTITY_ID: entity.entity_id, ATTR_VALUE: 200.4}, blocking=True, ) assert len(mock_set_tool_temp.mock_calls) == 1 # Verify that we pass integer, expected by the pyoctoprintapi mock_set_tool_temp.assert_called_with("tool0", 200) @pytest.mark.parametrize( "printer", [ { "state": { "flags": {"printing": False}, "text": "Operational", }, "temperature": {"bed": {"actual": 20.0, "target": 50.0}}, }, ], ) @pytest.mark.freeze_time(datetime(2020, 2, 20, 9, 10, 0)) @pytest.mark.usefixtures("init_integration") async def test_set_bed_temp( hass: HomeAssistant, ) -> None: """Test setting bed temperature via number entity.""" with patch( "pyoctoprintapi.OctoprintClient.set_bed_temperature" ) as mock_set_bed_temp: entity_component = hass.data[NUMBER_DOMAIN] entity = entity_component.get_entity("number.octoprint_bed_temperature") assert entity is not None await hass.services.async_call( NUMBER_DOMAIN, SERVICE_SET_VALUE, {ATTR_ENTITY_ID: entity.entity_id, ATTR_VALUE: 80.6}, blocking=True, ) assert len(mock_set_bed_temp.mock_calls) == 1 # Verify that we pass integer, expected by the pyoctoprintapi, and that it's rounded down mock_set_bed_temp.assert_called_with(80) @pytest.mark.parametrize( "printer", [ { "state": { "flags": {"printing": False}, "text": "Operational", }, "temperature": { "tool0": {"actual": 20.0, "target": 30.0}, "tool1": {"actual": 21.0, "target": 31.0}, }, }, ], ) @pytest.mark.freeze_time(datetime(2020, 2, 20, 9, 10, 0)) @pytest.mark.usefixtures("init_integration") async def test_set_tool_n_temp( hass: HomeAssistant, ) -> None: """Test setting tool temperature via number entity when multiple tools are present.""" with patch( "pyoctoprintapi.OctoprintClient.set_tool_temperature" ) as mock_set_tool_temp: entity_component = hass.data[NUMBER_DOMAIN] entity = entity_component.get_entity("number.octoprint_extruder_1_temperature") assert entity is not None await hass.services.async_call( NUMBER_DOMAIN, SERVICE_SET_VALUE, {ATTR_ENTITY_ID: entity.entity_id, ATTR_VALUE: 41.0}, blocking=True, ) assert len(mock_set_tool_temp.mock_calls) == 1 # Verify that we pass integer, expected by the pyoctoprintapi mock_set_tool_temp.assert_called_with("tool1", 41) @pytest.mark.parametrize("printer", [None]) @pytest.mark.freeze_time(datetime(2020, 2, 20, 9, 10, 0)) @pytest.mark.usefixtures("init_integration") async def test_numbers_printer_disconnected( hass: HomeAssistant, ) -> None: """Test number entities when printer is disconnected.""" # When printer is disconnected, no number entities should be created state = hass.states.get("number.octoprint_tool0_temperature") assert state is None state = hass.states.get("number.octoprint_bed_temperature") assert state is None def __standard_job(): return { "job": { "averagePrintTime": 6500, "estimatedPrintTime": 6000, "filament": {"tool0": {"length": 3000, "volume": 7}}, "file": { "date": 1577836800, "display": "Test File Name", "name": "Test_File_Name.gcode", "origin": "local", "path": "Folder1/Folder2/Test_File_Name.gcode", "size": 123456789, }, "lastPrintTime": 12345.678, "user": "testUser", }, "progress": {"completion": 50, "printTime": 600, "printTimeLeft": 6000}, "state": "Printing", }