Fix dashboard MQTT connection and remove simulation code
- Replace SimpleMqtt simulation with real MqttSubscriber - Fix String.split bug when handling MQTT topic parsing - Use hostname-based client ID to avoid MQTT client conflicts - Add process management tools (hivemind, just) to development environment 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
400270ae52
commit
c8e8e1dc24
@ -13,8 +13,8 @@ defmodule Dashboard.Application do
|
||||
{Phoenix.PubSub, name: Dashboard.PubSub},
|
||||
# Start the Finch HTTP client for sending emails
|
||||
{Finch, name: Dashboard.Finch},
|
||||
# Start simple MQTT subscriber
|
||||
Dashboard.SimpleMqtt,
|
||||
# Start real MQTT subscriber
|
||||
Dashboard.MqttSubscriber,
|
||||
# Start to serve requests, typically the last entry
|
||||
DashboardWeb.Endpoint
|
||||
]
|
||||
|
||||
@ -19,17 +19,27 @@ defmodule Dashboard.MqttSubscriber do
|
||||
|
||||
@impl true
|
||||
def init(_opts) do
|
||||
# Start MQTT connection in a supervised way
|
||||
{:ok, _pid} = Tortoise.Supervisor.start_child(
|
||||
:dashboard_mqtt,
|
||||
client_id: :dashboard_mqtt,
|
||||
# Start MQTT connection directly with hostname-based client ID to avoid conflicts
|
||||
{:ok, hostname} = :inet.gethostname()
|
||||
client_id = "systant-dashboard-#{hostname}"
|
||||
connection_opts = [
|
||||
client_id: client_id,
|
||||
server: {Tortoise.Transport.Tcp, host: "mqtt.home", port: 1883},
|
||||
handler: {__MODULE__, []},
|
||||
subscriptions: [{"systant/+/stats", 0}]
|
||||
)
|
||||
]
|
||||
|
||||
Logger.info("Dashboard MQTT subscriber started")
|
||||
{:ok, %{hosts: %{}}}
|
||||
case Tortoise.Connection.start_link(connection_opts) do
|
||||
{:ok, _pid} ->
|
||||
Logger.info("Dashboard MQTT subscriber connected successfully")
|
||||
{:ok, %{hosts: %{}}}
|
||||
{:error, {:already_started, _pid}} ->
|
||||
Logger.info("Dashboard MQTT connection already exists, reusing")
|
||||
{:ok, %{hosts: %{}}}
|
||||
{:error, reason} ->
|
||||
Logger.error("Failed to connect to MQTT broker: #{inspect(reason)}")
|
||||
{:stop, reason}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
@ -43,11 +53,19 @@ defmodule Dashboard.MqttSubscriber do
|
||||
end
|
||||
|
||||
# Tortoise handler callbacks
|
||||
def connection(_status, _state), do: []
|
||||
def subscription(_status, _topic, _state), do: []
|
||||
def connection(status, state) do
|
||||
Logger.info("MQTT connection status: #{status}")
|
||||
{:ok, state}
|
||||
end
|
||||
|
||||
def subscription(status, topic, state) do
|
||||
Logger.info("MQTT subscription status for #{topic}: #{status}")
|
||||
{:ok, state}
|
||||
end
|
||||
|
||||
def handle_message(topic, payload, _state) do
|
||||
case String.split(topic, "/") do
|
||||
topic_parts = if is_binary(topic), do: String.split(topic, "/"), else: topic
|
||||
case topic_parts do
|
||||
["systant", hostname, "stats"] ->
|
||||
case Jason.decode(payload) do
|
||||
{:ok, data} ->
|
||||
@ -74,5 +92,6 @@ defmodule Dashboard.MqttSubscriber do
|
||||
{:noreply, %{state | hosts: updated_hosts}}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def terminate(_reason, _state), do: []
|
||||
end
|
||||
@ -1,42 +0,0 @@
|
||||
defmodule Dashboard.SimpleMqtt do
|
||||
@moduledoc """
|
||||
Simple GenServer that polls for MQTT data instead of complex subscriptions.
|
||||
"""
|
||||
use GenServer
|
||||
require Logger
|
||||
|
||||
alias Phoenix.PubSub
|
||||
|
||||
def start_link(_opts) do
|
||||
GenServer.start_link(__MODULE__, [], name: __MODULE__)
|
||||
end
|
||||
|
||||
@impl true
|
||||
def init(_) do
|
||||
# Start a timer that simulates receiving MQTT data
|
||||
# In a real implementation, you'd use a proper MQTT client here
|
||||
Logger.info("Starting simple MQTT poller")
|
||||
|
||||
# For now, just generate fake data that matches what systant publishes
|
||||
:timer.send_interval(5000, self(), :simulate_mqtt)
|
||||
|
||||
{:ok, %{}}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_info(:simulate_mqtt, state) do
|
||||
# Simulate receiving an MQTT message from orion
|
||||
hostname = "orion"
|
||||
host_data = %{
|
||||
"message" => "Hello from systant",
|
||||
"hostname" => hostname,
|
||||
"timestamp" => DateTime.utc_now() |> DateTime.to_iso8601(),
|
||||
"last_seen" => DateTime.utc_now()
|
||||
}
|
||||
|
||||
Logger.info("Simulating MQTT message from #{hostname}")
|
||||
PubSub.broadcast(Dashboard.PubSub, "systant:hosts", {:host_update, hostname, host_data})
|
||||
|
||||
{:noreply, state}
|
||||
end
|
||||
end
|
||||
12
flake.nix
12
flake.nix
@ -27,13 +27,20 @@
|
||||
elixir
|
||||
erlang
|
||||
|
||||
# File watching for Phoenix live reload
|
||||
inotifyTools
|
||||
|
||||
# Process management and task running
|
||||
hivemind
|
||||
just
|
||||
|
||||
# AI/Development tools
|
||||
claude-code
|
||||
aider-chat
|
||||
|
||||
# Node.js for Phoenix assets
|
||||
nodejs_20
|
||||
npm
|
||||
nodePackages.npm
|
||||
|
||||
# Database for development
|
||||
postgresql
|
||||
@ -69,7 +76,8 @@
|
||||
};
|
||||
};
|
||||
}
|
||||
) // {
|
||||
)
|
||||
// {
|
||||
nixosModules.default = import ./nix/nixos-module.nix;
|
||||
};
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user