144 lines
3.9 KiB
Elixir
144 lines
3.9 KiB
Elixir
defmodule GeoTherminator.PumpAPI.Device.Server do
|
|
require Logger
|
|
require GeoTherminator.PumpAPI.Auth.InstallationInfo
|
|
|
|
use GenServer
|
|
import GeoTherminator.TypedStruct
|
|
alias GeoTherminator.PumpAPI.Device
|
|
alias GeoTherminator.PumpAPI.Auth.InstallationInfo
|
|
alias GeoTherminator.PumpAPI.Auth.Server, as: AuthServer
|
|
|
|
defmodule Options do
|
|
deftypedstruct(%{
|
|
auth_server: GenServer.name(),
|
|
installation: InstallationInfo.t()
|
|
})
|
|
end
|
|
|
|
defmodule State do
|
|
deftypedstruct(%{
|
|
auth_server: GenServer.name(),
|
|
device: {Device.t() | nil, nil},
|
|
status: {Device.Status.t() | nil, nil},
|
|
registers: {Device.RegisterCollection.t() | nil, nil},
|
|
opstat: {Device.OpStat.t() | nil, nil}
|
|
})
|
|
end
|
|
|
|
@spec start_link(Options.t()) :: GenServer.on_start()
|
|
def start_link(opts) do
|
|
GenServer.start_link(__MODULE__, opts,
|
|
name: {:via, Registry, {Device.Registry, InstallationInfo.record(opts.installation, :id)}}
|
|
)
|
|
end
|
|
|
|
@impl true
|
|
def init(%Options{} = opts) do
|
|
{:ok, %State{auth_server: opts.auth_server}, {:continue, {:init, opts.installation}}}
|
|
end
|
|
|
|
@impl true
|
|
def handle_continue({:init, installation}, state) do
|
|
user = AuthServer.get_auth(state.auth_server)
|
|
{:ok, device} = :pump_api@device@api.device_info(user, installation)
|
|
:ok = Device.PubSub.broadcast_device(device)
|
|
|
|
state =
|
|
%State{state | device: device}
|
|
|> refresh_status()
|
|
|
|
schedule_status()
|
|
{:noreply, state}
|
|
end
|
|
|
|
@impl true
|
|
def handle_call(msg, from, state)
|
|
|
|
def handle_call(:get_device, _from, state) do
|
|
{:reply, state.device, state}
|
|
end
|
|
|
|
def handle_call(:get_status, _from, state) do
|
|
{:reply, state.status, state}
|
|
end
|
|
|
|
def handle_call(:get_registers, _from, state) do
|
|
{:reply, state.registers, state}
|
|
end
|
|
|
|
def handle_call(:get_opstat, _from, state) do
|
|
{:reply, state.opstat, state}
|
|
end
|
|
|
|
def handle_call({:set_temp, temp}, _from, state) do
|
|
user = AuthServer.get_auth(state.auth_server)
|
|
|
|
Logger.debug("Begin set temp to #{temp}")
|
|
resp = :pump_api@device@api.set_temp(user, state.device, temp)
|
|
Logger.debug("Set temp result: #{inspect(resp)}")
|
|
{:reply, resp, state}
|
|
end
|
|
|
|
@impl true
|
|
def handle_info(msg, state)
|
|
|
|
def handle_info(:refresh_status, state) do
|
|
state = refresh_status(state)
|
|
schedule_status()
|
|
{:noreply, state}
|
|
end
|
|
|
|
@spec get_device(GenServer.name()) :: Device.t()
|
|
def get_device(server) do
|
|
GenServer.call(server, :get_device)
|
|
end
|
|
|
|
@spec get_status(GenServer.name()) :: Device.Status.t()
|
|
def get_status(server) do
|
|
GenServer.call(server, :get_status)
|
|
end
|
|
|
|
@spec get_registers(GenServer.name()) :: Device.RegisterCollection.t()
|
|
def get_registers(server) do
|
|
GenServer.call(server, :get_registers)
|
|
end
|
|
|
|
@spec get_opstat(GenServer.name()) :: Device.OpStat.t()
|
|
def get_opstat(server) do
|
|
GenServer.call(server, :get_opstat)
|
|
end
|
|
|
|
@spec set_temp(GenServer.name(), integer()) :: :ok | {:error, String.t()}
|
|
def set_temp(server, temp) do
|
|
GenServer.call(server, {:set_temp, temp})
|
|
end
|
|
|
|
defp refresh_status(state) do
|
|
user = AuthServer.get_auth(state.auth_server)
|
|
|
|
[status, registers, opstat] =
|
|
Task.async_stream(
|
|
[
|
|
&:pump_api@device@api.status/2,
|
|
&:pump_api@device@api.register_info/2,
|
|
&:pump_api@device@api.opstat/2
|
|
],
|
|
& &1.(user, state.device),
|
|
timeout: Application.fetch_env!(:geo_therminator, :api_timeout)
|
|
)
|
|
|> Enum.map(fn {:ok, {:ok, val}} -> val end)
|
|
|
|
Device.PubSub.broadcast_status(state.device, status)
|
|
Device.PubSub.broadcast_registers(state.device, registers)
|
|
Device.PubSub.broadcast_opstat(state.device, opstat)
|
|
%State{state | status: status, registers: registers, opstat: opstat}
|
|
end
|
|
|
|
defp schedule_status() do
|
|
Process.send_after(
|
|
self(),
|
|
:refresh_status,
|
|
Application.fetch_env!(:geo_therminator, :api_refresh)
|
|
)
|
|
end
|
|
end
|