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},
|
{Phoenix.PubSub, name: Dashboard.PubSub},
|
||||||
# Start the Finch HTTP client for sending emails
|
# Start the Finch HTTP client for sending emails
|
||||||
{Finch, name: Dashboard.Finch},
|
{Finch, name: Dashboard.Finch},
|
||||||
# Start simple MQTT subscriber
|
# Start real MQTT subscriber
|
||||||
Dashboard.SimpleMqtt,
|
Dashboard.MqttSubscriber,
|
||||||
# Start to serve requests, typically the last entry
|
# Start to serve requests, typically the last entry
|
||||||
DashboardWeb.Endpoint
|
DashboardWeb.Endpoint
|
||||||
]
|
]
|
||||||
|
|||||||
@ -19,17 +19,27 @@ defmodule Dashboard.MqttSubscriber do
|
|||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def init(_opts) do
|
def init(_opts) do
|
||||||
# Start MQTT connection in a supervised way
|
# Start MQTT connection directly with hostname-based client ID to avoid conflicts
|
||||||
{:ok, _pid} = Tortoise.Supervisor.start_child(
|
{:ok, hostname} = :inet.gethostname()
|
||||||
:dashboard_mqtt,
|
client_id = "systant-dashboard-#{hostname}"
|
||||||
client_id: :dashboard_mqtt,
|
connection_opts = [
|
||||||
|
client_id: client_id,
|
||||||
server: {Tortoise.Transport.Tcp, host: "mqtt.home", port: 1883},
|
server: {Tortoise.Transport.Tcp, host: "mqtt.home", port: 1883},
|
||||||
handler: {__MODULE__, []},
|
handler: {__MODULE__, []},
|
||||||
subscriptions: [{"systant/+/stats", 0}]
|
subscriptions: [{"systant/+/stats", 0}]
|
||||||
)
|
]
|
||||||
|
|
||||||
Logger.info("Dashboard MQTT subscriber started")
|
case Tortoise.Connection.start_link(connection_opts) do
|
||||||
{:ok, %{hosts: %{}}}
|
{: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
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
@ -43,11 +53,19 @@ defmodule Dashboard.MqttSubscriber do
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Tortoise handler callbacks
|
# Tortoise handler callbacks
|
||||||
def connection(_status, _state), do: []
|
def connection(status, state) do
|
||||||
def subscription(_status, _topic, _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
|
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"] ->
|
["systant", hostname, "stats"] ->
|
||||||
case Jason.decode(payload) do
|
case Jason.decode(payload) do
|
||||||
{:ok, data} ->
|
{:ok, data} ->
|
||||||
@ -74,5 +92,6 @@ defmodule Dashboard.MqttSubscriber do
|
|||||||
{:noreply, %{state | hosts: updated_hosts}}
|
{:noreply, %{state | hosts: updated_hosts}}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
def terminate(_reason, _state), do: []
|
def terminate(_reason, _state), do: []
|
||||||
end
|
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
|
elixir
|
||||||
erlang
|
erlang
|
||||||
|
|
||||||
|
# File watching for Phoenix live reload
|
||||||
|
inotifyTools
|
||||||
|
|
||||||
|
# Process management and task running
|
||||||
|
hivemind
|
||||||
|
just
|
||||||
|
|
||||||
# AI/Development tools
|
# AI/Development tools
|
||||||
claude-code
|
claude-code
|
||||||
aider-chat
|
aider-chat
|
||||||
|
|
||||||
# Node.js for Phoenix assets
|
# Node.js for Phoenix assets
|
||||||
nodejs_20
|
nodejs_20
|
||||||
npm
|
nodePackages.npm
|
||||||
|
|
||||||
# Database for development
|
# Database for development
|
||||||
postgresql
|
postgresql
|
||||||
@ -69,7 +76,8 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
) // {
|
)
|
||||||
|
// {
|
||||||
nixosModules.default = import ./nix/nixos-module.nix;
|
nixosModules.default = import ./nix/nixos-module.nix;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user