Current section

Files

Jump to
prusa_link lib prusa_link printer.ex
Raw

lib/prusa_link/printer.ex

defmodule PrusaLink.Printer do
@moduledoc """
Representation of a Prusa 3D printer and how to connect to it.
"""
alias PrusaLink.Printer
alias PrusaLink.Api
defstruct [:client, :name, :api_version, :capabilities, :nozzle, :mmu, :serial]
@doc """
Create a new printer representation.
It tries to connect to two endpoints (version & info) to retrieve meta information.
Returns a %PrusaLink.Printer{} struct including the information to connect to the printer as well as some meta information.
If the printer can not be reached it returns a tuple with {:unreachable, %Printer{}}.
The printer struct can still be used to connect to the printer later assuming the giving information is correct.
"""
@spec new(host_or_ip :: binary(), password :: binary()) ::
{:ok,
%PrusaLink.Printer{
client: Tesla.Client.t(),
api_version: integer()
}}
| {:not_reachable,
%PrusaLink.Printer{
client: Tesla.Client.t(),
api_version: integer()
}}
| {:error, reason :: any()}
def new(_host_or_ip, nil), do: {:error, :no_password}
def new(host_or_ip, password) do
Tesla.client(
[
{Tesla.Middleware.BaseUrl, "http://#{host_or_ip}"},
{Tesla.Middleware.DecodeJson, engine_opts: [keys: :atoms]},
{Tesla.Middleware.Headers, [{"X-Api-Key", password}]},
{Tesla.Middleware.Timeout, timeout: 5_000}
# {Tesla.Middleware.BasicAuth, %{username: user, password: password}}
],
Tesla.Adapter.Mint
)
|> fetch_printer_info()
end
@doc """
Connect to the printer to update meta data and specs.
Useful if you called `PrusaLink.Printer.new/2` before and received a `{:not_reachable, printer_struct}`,
you can pass the printer_struct in and try again.
"""
@doc since: "0.1.3"
@spec refresh(%Printer{}) ::
{:ok,
%PrusaLink.Printer{
client: Tesla.Client.t(),
api_version: integer()
}}
| {:not_reachable,
%PrusaLink.Printer{
client: Tesla.Client.t(),
api_version: integer()
}}
| {:error, reason :: any()}
def refresh(%__MODULE__{client: client}) do
fetch_printer_info(client)
end
@doc """
Retuns the meta information retrieved from the printer when connecting to it the first time.
## Examples
iex> PrusaLink.Printer.specs(mk4)
%{
name: "prusa-mk4",
serial: "1234567890",
api_version: 1,
capabilities: %{"upload-by-put": true},
nozzle: 0.4,
mmu: false
}
"""
@spec specs(%Printer{}) :: map()
def specs(%__MODULE__{} = printer) do
printer
|> Map.from_struct()
|> Map.drop([:client])
end
defp fetch_printer_info(client) do
with {:ok, version_resp} <- Api.api_version(client),
{:ok, info_resp} <- Api.info(client, 1) do
{:ok, build_printer(client, version_resp, info_resp)}
else
{:error, {:error, :timeout}} ->
{:not_reachable, struct(__MODULE__, %{client: client, api_version: 1})}
{:error, {:error, %Mint.TransportError{reason: reason}}}
when reason in [:ehostunreach, :ehostdown] ->
{:not_reachable, struct(__MODULE__, %{client: client, api_version: 1})}
{:error, error} ->
{:error, error}
end
end
defp build_printer(client, version_resp, info_resp) do
fields = %{
client: client,
name: version_resp[:hostname],
# api_version: version_resp["api"],
api_version: 1,
capabilities: version_resp[:capabilities],
nozzle: version_resp[:nozzle_diameter],
mmu: info_resp[:mmu],
serial: info_resp[:serial]
}
struct(__MODULE__, fields)
end
end