Files
mars3142_collection/plugin/actions/CopilotAction.js
T
mars3142 b635fdb981 railway over mqtt
change copilot to mqtt

Signed-off-by: Peter Siegmund <developer@mars3142.org>
2026-04-11 21:02:36 +02:00

176 lines
4.7 KiB
JavaScript

class CopilotAction extends ActionBase {
constructor($UD, context) {
super($UD, context);
this.config = { uri: '', username: '', password: '', topic: '' };
this.mqttClient = null;
this.value = null;
this.isError = false;
this.$UD.onDidReceiveSettings(jsn => {
if (jsn.context !== this.context) return;
const s = jsn.settings || {};
const prevKey = this.connectionKey();
this.config = Object.assign(this.config, s);
if (this.connectionKey() !== prevKey) {
this.connectMqtt();
}
});
}
connectionKey() {
return `${this.config.uri}|${this.config.username}|${this.config.topic}`;
}
setActive() {}
setParams(jsn) {
this.config = Object.assign(this.config, (jsn && jsn.param) || {});
this.$UD.getSettings(this.context);
this.connectMqtt();
}
onRun() {
if (!this.mqttClient || !this.mqttClient.connected) {
this.connectMqtt();
}
}
onClear() {
super.onClear();
this.disconnectMqtt();
}
disconnectMqtt() {
if (this.mqttClient) {
this.mqttClient.end(true);
this.mqttClient = null;
}
}
connectMqtt() {
this.disconnectMqtt();
if (!this.config.uri || !this.config.topic) {
this.renderGauge(null, false);
return;
}
try {
const opts = {
reconnectPeriod: 3000,
rejectUnauthorized: false,
};
if (this.config.username) opts.username = this.config.username;
if (this.config.password) opts.password = this.config.password;
this.mqttClient = mqtt.connect(this.config.uri, opts);
this.mqttClient.on('connect', () => {
this.isError = false;
this.mqttClient.subscribe(this.config.topic);
this.renderGauge(this.value, false);
});
this.mqttClient.on('message', (topic, payload) => {
try {
const msg = JSON.parse(payload.toString());
if (msg.usage != null) {
this.value = parseFloat(msg.usage);
this.isError = false;
} else {
this.isError = true;
}
this.renderGauge(this.value, this.isError);
} catch (e) {
this.renderGauge(null, true);
}
});
this.mqttClient.on('reconnect', () => {
this.renderGauge(this.value, false);
});
this.mqttClient.on('error', () => {
this.isError = true;
this.renderGauge(null, true);
});
this.renderGauge(this.value, false);
} catch (e) {
this.mqttClient = null;
this.renderGauge(null, true);
}
}
renderGauge(value, isError) {
const { canvas, ctx } = this.createCanvas();
const cx = 98, cy = 100;
const r = 68;
const lineWidth = 14;
const startAngle = 135 * Math.PI / 180;
const totalSweep = 270 * Math.PI / 180;
const greenEnd = startAngle + 0.50 * totalSweep;
const yellowEnd = startAngle + 0.80 * totalSweep;
const endAngle = startAngle + totalSweep;
// Background track
ctx.beginPath();
ctx.arc(cx, cy, r, startAngle, endAngle, false);
ctx.strokeStyle = '#333333';
ctx.lineWidth = lineWidth;
ctx.lineCap = 'round';
ctx.stroke();
const connected = this.mqttClient && this.mqttClient.connected;
if (value !== null && !isError && connected) {
const pct = Math.max(0, Math.min(100, value)) / 100;
const valueAngle = startAngle + pct * totalSweep;
if (pct > 0) {
ctx.beginPath();
ctx.arc(cx, cy, r, startAngle, Math.min(valueAngle, greenEnd), false);
ctx.strokeStyle = '#4caf50';
ctx.lineWidth = lineWidth;
ctx.lineCap = 'round';
ctx.stroke();
}
if (pct > 0.5) {
ctx.beginPath();
ctx.arc(cx, cy, r, greenEnd, Math.min(valueAngle, yellowEnd), false);
ctx.strokeStyle = '#ffeb3b';
ctx.lineWidth = lineWidth;
ctx.lineCap = 'butt';
ctx.stroke();
}
if (pct > 0.8) {
ctx.beginPath();
ctx.arc(cx, cy, r, yellowEnd, valueAngle, false);
ctx.strokeStyle = '#f44336';
ctx.lineWidth = lineWidth;
ctx.lineCap = 'butt';
ctx.stroke();
}
const color = pct <= 0.5 ? '#4caf50' : pct <= 0.8 ? '#ffeb3b' : '#f44336';
const displayText = value.toFixed(1) + '%';
const fSize = displayText.length > 5 ? 28 : 34;
ctx.fillStyle = color;
ctx.font = `bold ${fSize}px "Source Han Sans SC"`;
ctx.fillText(displayText, cx, cy);
} else {
ctx.fillStyle = isError ? '#ff6b6b' : '#666666';
ctx.font = 'bold 28px "Source Han Sans SC"';
ctx.fillText(isError ? 'ERR' : 'N/A', cx, cy);
}
// Label — bottom
ctx.fillStyle = '#7ec8e3';
ctx.font = 'bold 20px "Source Han Sans SC"';
ctx.fillText('Copilot', cx, 165);
this.setIcon(canvas);
}
}