139 lines
3.6 KiB
Elixir
139 lines
3.6 KiB
Elixir
|
defmodule GeoTherminator.PumpAPI.Device.Server do
|
||
|
use GenServer
|
||
|
import GeoTherminator.TypedStruct
|
||
|
alias GeoTherminator.PumpAPI.Device
|
||
|
alias GeoTherminator.PumpAPI.Auth.InstallationInfo
|
||
|
alias GeoTherminator.PumpAPI.Auth.Server, as: AuthServer
|
||
|
require Logger
|
||
|
|
||
|
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, 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)
|
||
|
device = 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 = 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(
|
||
|
[&Device.API.status/2, &Device.API.register_info/2, &Device.API.opstat/2],
|
||
|
& &1.(user, state.device)
|
||
|
)
|
||
|
|> Enum.map(fn {: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.get_env(:geo_therminator, :api_refresh)
|
||
|
)
|
||
|
end
|
||
|
end
|