async function createPlugin(ctx) { let lastAzimuth = Number(ctx.getSetting("defaultAzimuth", ctx.env.ROTOR_DEFAULT_AZIMUTH || 0)); const simulate = typeof ctx.simulateHardware === "boolean" ? ctx.simulateHardware : (process.platform !== "linux" && String(ctx.env.ALLOW_NON_LINUX_CMDS || "false") !== "true"); return { async execute(action, input) { if (action === "getAzimuth") { return getRotorStatus(ctx, simulate, () => lastAzimuth, (value) => { lastAzimuth = value; }); } if (action !== "setAzimuth") { throw new Error(`Unknown action: ${action}`); } const target = Number(input && input.target); if (!Number.isFinite(target) || target < 0 || target > 360) { throw new Error("target muss zwischen 0 und 360 sein"); } const template = String(ctx.getSetting("setTemplate", ctx.env.ROTOR_SET_CMD_TEMPLATE || "")).trim(); if (template) { if (simulate) { lastAzimuth = target; return { ok: true, skipped: true, message: `Rotor auf ${target} Grad simuliert (${ctx.execMode || "dev"})` }; } const command = template.replace(/\{az\}/g, String(target)); const result = await ctx.commandRunner(command, { timeoutMs: Number(ctx.env.ROTOR_SET_TIMEOUT_MS || 20000) }); if (!result.ok) { throw new Error(result.stderr || result.error || "Rotor set failed"); } } lastAzimuth = target; ctx.emit("ui.control.state.changed", { controlId: "rotor-main", data: { azimuth: lastAzimuth, moving: false } }); return { ok: true, message: `Rotor auf ${target} Grad gesetzt` }; }, async getStatus() { return getRotorStatus(ctx, simulate, () => lastAzimuth, (value) => { lastAzimuth = value; }); }, async health() { return { ok: true }; } }; } async function getRotorStatus(ctx, simulate, getLastAzimuth, setLastAzimuth) { const getCmd = String(ctx.getSetting("getCommand", ctx.env.ROTOR_GET_CMD || "")).trim(); if (getCmd) { if (simulate) { return { azimuth: getLastAzimuth(), moving: false, min: 0, max: 360 }; } const result = await ctx.commandRunner(getCmd, { timeoutMs: Number(ctx.env.ROTOR_GET_TIMEOUT_MS || 10000) }); if (result.ok) { const parsed = Number(String(result.stdout).split(/\s+/)[0]); if (Number.isFinite(parsed)) { setLastAzimuth(parsed < 0 ? parsed + 360 : parsed); } } } return { azimuth: getLastAzimuth(), moving: false, min: 0, max: 360 }; } module.exports = { createPlugin };