diff --git a/custom_components/moonraker/__init__.py b/custom_components/moonraker/__init__.py index cb8414f..9caf175 100755 --- a/custom_components/moonraker/__init__.py +++ b/custom_components/moonraker/__init__.py @@ -19,6 +19,7 @@ CONF_API_KEY, CONF_PORT, CONF_PRINTER_NAME, + CONF_TLS, CONF_URL, DOMAIN, HOSTNAME, @@ -60,13 +61,18 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): url = entry.data.get(CONF_URL) port = entry.data.get(CONF_PORT) + tls = entry.data.get(CONF_TLS) api_key = entry.data.get(CONF_API_KEY) printer_name = ( entry.data.get(CONF_PRINTER_NAME) if custom_name is None else custom_name ) api = MoonrakerApiClient( - url, async_get_clientsession(hass, verify_ssl=False), port=port, api_key=api_key + url, + async_get_clientsession(hass, verify_ssl=False), + port=port, + api_key=api_key, + tls=tls, ) try: diff --git a/custom_components/moonraker/api.py b/custom_components/moonraker/api.py index 026c24f..cda40e7 100755 --- a/custom_components/moonraker/api.py +++ b/custom_components/moonraker/api.py @@ -6,14 +6,21 @@ class MoonrakerApiClient(MoonrakerListener): """Moonraker communication API""" - def __init__(self, url, session, port: int = 7125, api_key: str = None): + def __init__( + self, url, session, port: int = 7125, api_key: str = None, tls: bool = False + ): self.running = False if api_key == "": api_key = None if port is None: port = 7125 self.client = MoonrakerClient( - listener=self, host=url, port=port, session=session, api_key=api_key + listener=self, + host=url, + port=port, + session=session, + api_key=api_key, + ssl=tls, ) async def start(self) -> None: diff --git a/custom_components/moonraker/config_flow.py b/custom_components/moonraker/config_flow.py index 7c9fcbf..0d484af 100755 --- a/custom_components/moonraker/config_flow.py +++ b/custom_components/moonraker/config_flow.py @@ -8,7 +8,15 @@ import voluptuous as vol from .api import MoonrakerApiClient -from .const import CONF_API_KEY, CONF_PORT, CONF_PRINTER_NAME, CONF_URL, DOMAIN, TIMEOUT +from .const import ( + CONF_API_KEY, + CONF_PORT, + CONF_PRINTER_NAME, + CONF_TLS, + CONF_URL, + DOMAIN, + TIMEOUT, +) _LOGGER = logging.getLogger(__name__) @@ -45,7 +53,10 @@ async def async_step_user(self, user_input=None): return await self._show_config_form(user_input) if not await self._test_connection( - user_input[CONF_URL], user_input[CONF_PORT], user_input[CONF_API_KEY] + user_input[CONF_URL], + user_input[CONF_PORT], + user_input[CONF_API_KEY], + user_input[CONF_TLS], ): self._errors[CONF_URL] = "printer_connection_error" return await self._show_config_form(user_input) @@ -57,6 +68,7 @@ async def async_step_user(self, user_input=None): # Provide defaults for form user_input[CONF_URL] = "192.168.1.123" user_input[CONF_PORT] = "7125" + user_input[CONF_TLS] = False user_input[CONF_API_KEY] = "" user_input[CONF_PRINTER_NAME] = "" @@ -72,6 +84,7 @@ async def _show_config_form(self, user_input): # pylint: disable=unused-argumen { vol.Required(CONF_URL, default=user_input[CONF_URL]): str, vol.Optional(CONF_PORT, default=user_input[CONF_PORT]): str, + vol.Optional(CONF_TLS, default=user_input[CONF_TLS]): bool, vol.Optional(CONF_API_KEY, default=user_input[CONF_API_KEY]): str, vol.Optional( CONF_PRINTER_NAME, default=user_input[CONF_PRINTER_NAME] @@ -104,12 +117,13 @@ async def _test_printer_name(self, printer_name): return True - async def _test_connection(self, host, port, api_key): + async def _test_connection(self, host, port, api_key, tls): api = MoonrakerApiClient( host, async_get_clientsession(self.hass, verify_ssl=False), port=port, api_key=api_key, + tls=tls, ) try: diff --git a/custom_components/moonraker/const.py b/custom_components/moonraker/const.py index f88f3c0..f5c0b81 100644 --- a/custom_components/moonraker/const.py +++ b/custom_components/moonraker/const.py @@ -22,6 +22,7 @@ CONF_API_KEY = "api_key" CONF_URL = "url" CONF_PORT = "port" +CONF_TLS = "tls" CONF_PRINTER_NAME = "printer_name" # API dict keys diff --git a/custom_components/moonraker/translations/en.json b/custom_components/moonraker/translations/en.json index 876242a..b6f31a5 100644 --- a/custom_components/moonraker/translations/en.json +++ b/custom_components/moonraker/translations/en.json @@ -6,6 +6,7 @@ "data": { "url": "Host", "port": "Port", + "tls": "Uses TLS", "api_key": "API Key (Optional)", "printer_name": "Printer's Name (Defaults to the hostname)" } diff --git a/docs/_static/connection-dialog.png b/docs/_static/connection-dialog.png new file mode 100644 index 0000000..5d7ca9e Binary files /dev/null and b/docs/_static/connection-dialog.png differ diff --git a/docs/connection.rst b/docs/connection.rst new file mode 100644 index 0000000..cc0fbfc --- /dev/null +++ b/docs/connection.rst @@ -0,0 +1,35 @@ +Connection properties +====================== + +The connection properties dialog can be used to connect to the Moonraker API. +The integration is capable of connecting to most Moonraker deployments. + +.. image:: _static/connection-dialog.png + :align: center + +Connection properties can be defined as follows: + +.. list-table:: Connection properties + :header-rows: 1 + + * - name + - default + - description + * - Host + - None, **(required)** + - IP address or hostname of Moonraker + * - Port + - 7125 + - Moonraker port + * - Uses TLS + - + - use encrypted connections + * - API Key + - + - Moonraker API key + * - Printer's Name + - Host address + - Device name in Home Assistant + +Note: Encrypted connections must be configured in Moonraker API or by using a +reverse proxy to connect to Moonraker API. \ No newline at end of file diff --git a/docs/index.rst b/docs/index.rst index 22cdac0..5ba702b 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -33,6 +33,7 @@ This software seems to have issues working on **FLSUN Speeder Pad** and **Sonic install dashboard + connection .. toctree:: :caption: Usage diff --git a/tests/const.py b/tests/const.py index cf1dcf8..2280fc4 100644 --- a/tests/const.py +++ b/tests/const.py @@ -3,6 +3,7 @@ CONF_API_KEY, CONF_PORT, CONF_PRINTER_NAME, + CONF_TLS, CONF_URL, ) @@ -10,6 +11,7 @@ MOCK_CONFIG = { CONF_URL: "1.2.3.4", CONF_PORT: "1234", + CONF_TLS: False, CONF_API_KEY: "", CONF_PRINTER_NAME: "", } @@ -17,6 +19,7 @@ MOCK_CONFIG_WITH_NAME = { CONF_URL: "1.2.3.4", CONF_PORT: "1234", + CONF_TLS: False, CONF_API_KEY: "", CONF_PRINTER_NAME: "example name", } diff --git a/tests/test_config_flow.py b/tests/test_config_flow.py index b5b86b5..8f807bd 100644 --- a/tests/test_config_flow.py +++ b/tests/test_config_flow.py @@ -8,6 +8,7 @@ CONF_API_KEY, CONF_PORT, CONF_PRINTER_NAME, + CONF_TLS, CONF_URL, DOMAIN, ) @@ -133,12 +134,36 @@ async def test_server_host_when_good(hass): assert result["data"] == { CONF_URL: "1.2.3.4", CONF_PORT: "7125", + CONF_TLS: False, CONF_API_KEY: "", CONF_PRINTER_NAME: "", } assert result["result"] +@pytest.mark.usefixtures("bypass_connect_client") +async def test_server_ssl_enabled(hass): + """Test server host with TLS.""" + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": config_entries.SOURCE_USER} + ) + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], user_input={CONF_URL: "1.2.3.4", CONF_TLS: True} + ) + + assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + assert result["title"] == DOMAIN + assert result["data"] == { + CONF_URL: "1.2.3.4", + CONF_PORT: "7125", + CONF_API_KEY: "", + CONF_TLS: True, + CONF_PRINTER_NAME: "", + } + assert result["result"] + + @pytest.mark.usefixtures("bypass_connect_client") async def test_server_port_too_low(hass): """Test server port when it's too low.""" @@ -194,6 +219,7 @@ async def test_server_port_when_good_port(hass): assert result["data"] == { CONF_URL: "1.2.3.4", CONF_PORT: "7611", + CONF_TLS: False, CONF_API_KEY: "", CONF_PRINTER_NAME: "", } @@ -216,6 +242,7 @@ async def test_server_port_when_port_empty(hass): assert result["data"] == { CONF_URL: "1.2.3.4", CONF_PORT: "", + CONF_TLS: False, CONF_API_KEY: "", CONF_PRINTER_NAME: "", } @@ -281,6 +308,7 @@ async def test_server_api_key_when_good(hass): assert result["data"] == { CONF_URL: "1.2.3.4", CONF_PORT: "7125", + CONF_TLS: False, CONF_API_KEY: "A7ylD3EuPWWxGlsshlCIJjzRBNbQzlre", CONF_PRINTER_NAME: "", } @@ -306,6 +334,7 @@ async def test_server_api_key_when_empty(hass): assert result["data"] == { CONF_URL: "1.2.3.4", CONF_PORT: "7125", + CONF_TLS: False, CONF_API_KEY: "", CONF_PRINTER_NAME: "", } @@ -343,6 +372,7 @@ async def test_printer_name_when_good(hass): assert result["data"] == { CONF_URL: "1.2.3.4", CONF_PORT: "7125", + CONF_TLS: False, CONF_API_KEY: "", CONF_PRINTER_NAME: "example name", }