Skip to content

Commit

Permalink
Add support for TLS connections (#210)
Browse files Browse the repository at this point in the history
* Add support for TLS connections

Add a toggle for connections that use TLS. this change makes it possible
to access HTTPS enabled printers.

* Add basic connection documentation

Document the default values and add a note that TLS must be configured
on the server side for them to work.
  • Loading branch information
ressu authored Oct 1, 2023
1 parent 9044226 commit ddaafe5
Show file tree
Hide file tree
Showing 10 changed files with 104 additions and 6 deletions.
8 changes: 7 additions & 1 deletion custom_components/moonraker/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
CONF_API_KEY,
CONF_PORT,
CONF_PRINTER_NAME,
CONF_TLS,
CONF_URL,
DOMAIN,
HOSTNAME,
Expand Down Expand Up @@ -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:
Expand Down
11 changes: 9 additions & 2 deletions custom_components/moonraker/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
20 changes: 17 additions & 3 deletions custom_components/moonraker/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__)

Expand Down Expand Up @@ -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)
Expand All @@ -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] = ""

Expand All @@ -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]
Expand Down Expand Up @@ -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:
Expand Down
1 change: 1 addition & 0 deletions custom_components/moonraker/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions custom_components/moonraker/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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)"
}
Expand Down
Binary file added docs/_static/connection-dialog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
35 changes: 35 additions & 0 deletions docs/connection.rst
Original file line number Diff line number Diff line change
@@ -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.
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ This software seems to have issues working on **FLSUN Speeder Pad** and **Sonic

install
dashboard
connection

.. toctree::
:caption: Usage
Expand Down
3 changes: 3 additions & 0 deletions tests/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,23 @@
CONF_API_KEY,
CONF_PORT,
CONF_PRINTER_NAME,
CONF_TLS,
CONF_URL,
)

# Mock config data to be used across multiple tests
MOCK_CONFIG = {
CONF_URL: "1.2.3.4",
CONF_PORT: "1234",
CONF_TLS: False,
CONF_API_KEY: "",
CONF_PRINTER_NAME: "",
}

MOCK_CONFIG_WITH_NAME = {
CONF_URL: "1.2.3.4",
CONF_PORT: "1234",
CONF_TLS: False,
CONF_API_KEY: "",
CONF_PRINTER_NAME: "example name",
}
30 changes: 30 additions & 0 deletions tests/test_config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
CONF_API_KEY,
CONF_PORT,
CONF_PRINTER_NAME,
CONF_TLS,
CONF_URL,
DOMAIN,
)
Expand Down Expand Up @@ -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."""
Expand Down Expand Up @@ -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: "",
}
Expand All @@ -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: "",
}
Expand Down Expand Up @@ -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: "",
}
Expand All @@ -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: "",
}
Expand Down Expand Up @@ -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",
}
Expand Down

0 comments on commit ddaafe5

Please sign in to comment.