iobroker.beszel 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/auto-merge.yml +2 -0
- package/.github/dependabot.yml +12 -0
- package/.github/workflows/automerge-dependabot.yml +32 -0
- package/.github/workflows/test-and-release.yml +62 -0
- package/.vscode/settings.json +12 -0
- package/CHANGELOG.md +13 -0
- package/CLAUDE.md +91 -0
- package/LICENSE +21 -0
- package/README.md +187 -0
- package/admin/beszel.svg +9 -0
- package/admin/i18n/de/translations.json +43 -0
- package/admin/i18n/en/translations.json +43 -0
- package/admin/i18n/es/translations.json +43 -0
- package/admin/i18n/fr/translations.json +43 -0
- package/admin/i18n/it/translations.json +43 -0
- package/admin/i18n/nl/translations.json +43 -0
- package/admin/i18n/pl/translations.json +43 -0
- package/admin/i18n/pt/translations.json +43 -0
- package/admin/i18n/ru/translations.json +43 -0
- package/admin/i18n/uk/translations.json +43 -0
- package/admin/i18n/zh-cn/translations.json +43 -0
- package/admin/jsonConfig.json +240 -0
- package/build/lib/beszel-client.d.ts +39 -0
- package/build/lib/beszel-client.d.ts.map +1 -0
- package/build/lib/beszel-client.js +199 -0
- package/build/lib/state-manager.d.ts +47 -0
- package/build/lib/state-manager.d.ts.map +1 -0
- package/build/lib/state-manager.js +738 -0
- package/build/lib/types.d.ts +174 -0
- package/build/lib/types.d.ts.map +1 -0
- package/build/lib/types.js +2 -0
- package/build/main.d.ts +2 -0
- package/build/main.d.ts.map +1 -0
- package/build/main.js +191 -0
- package/eslint.config.mjs +36 -0
- package/io-package.json +162 -0
- package/package.json +61 -0
- package/scripts/version.js +28 -0
- package/src/lib/beszel-client.ts +216 -0
- package/src/lib/state-manager.ts +1050 -0
- package/src/lib/types.ts +192 -0
- package/src/main.ts +199 -0
- package/test/testPackageFiles.ts +5 -0
- package/tsconfig.build.json +7 -0
- package/tsconfig.json +24 -0
- package/tsconfig.test.json +9 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapter configuration as stored in ioBroker native config
|
|
3
|
+
*/
|
|
4
|
+
export interface AdapterConfig {
|
|
5
|
+
url: string;
|
|
6
|
+
username: string;
|
|
7
|
+
password: string;
|
|
8
|
+
pollInterval: number;
|
|
9
|
+
metrics_uptime: boolean;
|
|
10
|
+
metrics_agentVersion: boolean;
|
|
11
|
+
metrics_services: boolean;
|
|
12
|
+
metrics_cpu: boolean;
|
|
13
|
+
metrics_loadAvg: boolean;
|
|
14
|
+
metrics_cpuBreakdown: boolean;
|
|
15
|
+
metrics_memory: boolean;
|
|
16
|
+
metrics_memoryDetails: boolean;
|
|
17
|
+
metrics_swap: boolean;
|
|
18
|
+
metrics_disk: boolean;
|
|
19
|
+
metrics_diskSpeed: boolean;
|
|
20
|
+
metrics_extraFs: boolean;
|
|
21
|
+
metrics_network: boolean;
|
|
22
|
+
metrics_temperature: boolean;
|
|
23
|
+
metrics_temperatureDetails: boolean;
|
|
24
|
+
metrics_gpu: boolean;
|
|
25
|
+
metrics_containers: boolean;
|
|
26
|
+
metrics_battery: boolean;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* System info object from Beszel systems record
|
|
30
|
+
*/
|
|
31
|
+
export interface SystemInfo {
|
|
32
|
+
/** Uptime in seconds */
|
|
33
|
+
u?: number;
|
|
34
|
+
/** Agent version */
|
|
35
|
+
v?: string;
|
|
36
|
+
/** Systemd services [total, failed] */
|
|
37
|
+
sv?: [number, number];
|
|
38
|
+
/** Load average [1m, 5m, 15m] */
|
|
39
|
+
la?: [number, number, number];
|
|
40
|
+
/** Battery [percent, charge_state] */
|
|
41
|
+
bat?: [number, number];
|
|
42
|
+
/** Connection type */
|
|
43
|
+
ct?: number;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* A system record from /api/collections/systems/records
|
|
47
|
+
*/
|
|
48
|
+
export interface BeszelSystem {
|
|
49
|
+
id: string;
|
|
50
|
+
name: string;
|
|
51
|
+
status: "up" | "down" | "paused" | "pending";
|
|
52
|
+
host: string;
|
|
53
|
+
info: SystemInfo;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Extra filesystem stats
|
|
57
|
+
*/
|
|
58
|
+
export interface FsStats {
|
|
59
|
+
/** disk total GB */
|
|
60
|
+
d?: number;
|
|
61
|
+
/** disk used GB */
|
|
62
|
+
du?: number;
|
|
63
|
+
/** read MB/s */
|
|
64
|
+
r?: number;
|
|
65
|
+
/** write MB/s */
|
|
66
|
+
w?: number;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* GPU data
|
|
70
|
+
*/
|
|
71
|
+
export interface GPUData {
|
|
72
|
+
/** GPU name */
|
|
73
|
+
n?: string;
|
|
74
|
+
/** GPU usage % */
|
|
75
|
+
u?: number;
|
|
76
|
+
/** GPU memory used GB */
|
|
77
|
+
mu?: number;
|
|
78
|
+
/** GPU memory total GB */
|
|
79
|
+
mt?: number;
|
|
80
|
+
/** GPU power W */
|
|
81
|
+
p?: number;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* The stats object inside a system_stats record
|
|
85
|
+
*/
|
|
86
|
+
export interface SystemStats {
|
|
87
|
+
/** CPU usage % */
|
|
88
|
+
cpu?: number;
|
|
89
|
+
/** RAM used GB */
|
|
90
|
+
mu?: number;
|
|
91
|
+
/** RAM total GB */
|
|
92
|
+
m?: number;
|
|
93
|
+
/** RAM % */
|
|
94
|
+
mp?: number;
|
|
95
|
+
/** Buffers + cache GB */
|
|
96
|
+
mb?: number;
|
|
97
|
+
/** ZFS ARC GB */
|
|
98
|
+
mz?: number;
|
|
99
|
+
/** Swap used GB */
|
|
100
|
+
su?: number;
|
|
101
|
+
/** Swap total GB */
|
|
102
|
+
s?: number;
|
|
103
|
+
/** Disk used GB */
|
|
104
|
+
du?: number;
|
|
105
|
+
/** Disk total GB */
|
|
106
|
+
d?: number;
|
|
107
|
+
/** Disk % */
|
|
108
|
+
dp?: number;
|
|
109
|
+
/** Disk read MB/s */
|
|
110
|
+
dr?: number;
|
|
111
|
+
/** Disk write MB/s */
|
|
112
|
+
dw?: number;
|
|
113
|
+
/** Network sent MB/s */
|
|
114
|
+
ns?: number;
|
|
115
|
+
/** Network recv MB/s */
|
|
116
|
+
nr?: number;
|
|
117
|
+
/** Temperatures map sensor->°C */
|
|
118
|
+
t?: Record<string, number>;
|
|
119
|
+
/** Load avg [1m, 5m, 15m] */
|
|
120
|
+
la?: [number, number, number];
|
|
121
|
+
/** GPU data */
|
|
122
|
+
g?: Record<string, GPUData>;
|
|
123
|
+
/** Extra filesystems */
|
|
124
|
+
efs?: Record<string, FsStats>;
|
|
125
|
+
/** Battery [%, charge_state] */
|
|
126
|
+
bat?: [number, number];
|
|
127
|
+
/** CPU breakdown [user, sys, iowait, steal, idle] % */
|
|
128
|
+
cpub?: number[];
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* A system_stats record from /api/collections/system_stats/records
|
|
132
|
+
*/
|
|
133
|
+
export interface BeszelSystemStats {
|
|
134
|
+
id: string;
|
|
135
|
+
system: string;
|
|
136
|
+
type: string;
|
|
137
|
+
stats: SystemStats;
|
|
138
|
+
updated: string;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* A container record from /api/collections/containers/records
|
|
142
|
+
*/
|
|
143
|
+
export interface BeszelContainer {
|
|
144
|
+
id: string;
|
|
145
|
+
system: string;
|
|
146
|
+
name: string;
|
|
147
|
+
status: string;
|
|
148
|
+
health: number;
|
|
149
|
+
cpu: number;
|
|
150
|
+
memory: number;
|
|
151
|
+
image: string;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* PocketBase list response
|
|
155
|
+
*/
|
|
156
|
+
export interface PocketBaseList<T> {
|
|
157
|
+
page: number;
|
|
158
|
+
perPage: number;
|
|
159
|
+
totalItems: number;
|
|
160
|
+
totalPages: number;
|
|
161
|
+
items: T[];
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* PocketBase auth response
|
|
165
|
+
*/
|
|
166
|
+
export interface AuthResponse {
|
|
167
|
+
token: string;
|
|
168
|
+
record: {
|
|
169
|
+
id: string;
|
|
170
|
+
email: string;
|
|
171
|
+
[key: string]: unknown;
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":"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"}
|
package/build/main.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":""}
|
package/build/main.js
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const utils = __importStar(require("@iobroker/adapter-core"));
|
|
37
|
+
const beszel_client_js_1 = require("./lib/beszel-client.js");
|
|
38
|
+
const state_manager_js_1 = require("./lib/state-manager.js");
|
|
39
|
+
class BeszelAdapter extends utils.Adapter {
|
|
40
|
+
client = null;
|
|
41
|
+
stateManager = null;
|
|
42
|
+
pollTimer = null;
|
|
43
|
+
isPolling = false;
|
|
44
|
+
constructor(options = {}) {
|
|
45
|
+
super({
|
|
46
|
+
...options,
|
|
47
|
+
name: "beszel",
|
|
48
|
+
});
|
|
49
|
+
this.on("ready", this.onReady.bind(this));
|
|
50
|
+
this.on("unload", this.onUnload.bind(this));
|
|
51
|
+
this.on("message", this.onMessage.bind(this));
|
|
52
|
+
}
|
|
53
|
+
async onReady() {
|
|
54
|
+
const config = this.config;
|
|
55
|
+
// Ensure info objects exist before any setState calls
|
|
56
|
+
await this.setObjectNotExistsAsync("info", {
|
|
57
|
+
type: "channel",
|
|
58
|
+
common: { name: "Information" },
|
|
59
|
+
native: {},
|
|
60
|
+
});
|
|
61
|
+
await this.setObjectNotExistsAsync("info.connection", {
|
|
62
|
+
type: "state",
|
|
63
|
+
common: {
|
|
64
|
+
name: "Connection status",
|
|
65
|
+
type: "boolean",
|
|
66
|
+
role: "indicator.connected",
|
|
67
|
+
read: true,
|
|
68
|
+
write: false,
|
|
69
|
+
def: false,
|
|
70
|
+
},
|
|
71
|
+
native: {},
|
|
72
|
+
});
|
|
73
|
+
await this.setStateAsync("info.connection", { val: false, ack: true });
|
|
74
|
+
// Validate required config
|
|
75
|
+
if (!config.url || !config.username || !config.password) {
|
|
76
|
+
this.log.error("Beszel adapter: URL, username, and password are required. Please configure the adapter.");
|
|
77
|
+
await this.setStateAsync("info.connection", { val: false, ack: true });
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
this.client = new beszel_client_js_1.BeszelClient(config.url, config.username, config.password);
|
|
81
|
+
this.stateManager = new state_manager_js_1.StateManager(this);
|
|
82
|
+
// Cleanup disabled metric states for existing systems (config may have changed)
|
|
83
|
+
const existingObjects = await this.getObjectViewAsync("system", "device", {
|
|
84
|
+
startkey: `${this.namespace}.systems.`,
|
|
85
|
+
endkey: `${this.namespace}.systems.\u9999`,
|
|
86
|
+
});
|
|
87
|
+
if (existingObjects?.rows) {
|
|
88
|
+
for (const row of existingObjects.rows) {
|
|
89
|
+
const relId = row.id.startsWith(`${this.namespace}.`)
|
|
90
|
+
? row.id.slice(this.namespace.length + 1)
|
|
91
|
+
: row.id;
|
|
92
|
+
const parts = relId.split(".");
|
|
93
|
+
if (parts.length === 2 && parts[0] === "systems") {
|
|
94
|
+
await this.stateManager.cleanupMetrics(parts[1], config);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// Initial poll
|
|
99
|
+
await this.poll();
|
|
100
|
+
// Set up recurring poll
|
|
101
|
+
const intervalMs = Math.max(10, config.pollInterval ?? 60) * 1000;
|
|
102
|
+
this.pollTimer = setInterval(() => {
|
|
103
|
+
void this.poll();
|
|
104
|
+
}, intervalMs);
|
|
105
|
+
this.log.info(`Beszel adapter started. Polling every ${config.pollInterval ?? 60}s from ${config.url}`);
|
|
106
|
+
}
|
|
107
|
+
async onUnload(callback) {
|
|
108
|
+
try {
|
|
109
|
+
if (this.pollTimer) {
|
|
110
|
+
clearInterval(this.pollTimer);
|
|
111
|
+
this.pollTimer = null;
|
|
112
|
+
}
|
|
113
|
+
await this.setStateAsync("info.connection", { val: false, ack: true });
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// ignore
|
|
117
|
+
}
|
|
118
|
+
callback();
|
|
119
|
+
}
|
|
120
|
+
async onMessage(obj) {
|
|
121
|
+
if (obj.command === "checkConnection") {
|
|
122
|
+
const config = obj.message;
|
|
123
|
+
const url = config.url ?? "";
|
|
124
|
+
const username = config.username ?? "";
|
|
125
|
+
const password = config.password ?? "";
|
|
126
|
+
if (!url || !username || !password) {
|
|
127
|
+
this.sendTo(obj.from, obj.command, {
|
|
128
|
+
success: false,
|
|
129
|
+
message: "URL, username and password are required",
|
|
130
|
+
}, obj.callback);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const testClient = new beszel_client_js_1.BeszelClient(url, username, password);
|
|
134
|
+
const result = await testClient.checkConnection();
|
|
135
|
+
this.sendTo(obj.from, obj.command, result, obj.callback);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
async poll() {
|
|
139
|
+
if (this.isPolling) {
|
|
140
|
+
this.log.debug("Skipping poll — previous poll still running");
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (!this.client || !this.stateManager) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
this.isPolling = true;
|
|
147
|
+
try {
|
|
148
|
+
const config = this.config;
|
|
149
|
+
// Fetch all data
|
|
150
|
+
const [systems, containers] = await Promise.all([
|
|
151
|
+
this.client.getSystems(),
|
|
152
|
+
config.metrics_containers
|
|
153
|
+
? this.client.getContainers()
|
|
154
|
+
: Promise.resolve([]),
|
|
155
|
+
]);
|
|
156
|
+
const systemIds = systems.map((s) => s.id);
|
|
157
|
+
const statsMap = await this.client.getLatestStats(systemIds);
|
|
158
|
+
// Update connection state
|
|
159
|
+
await this.setStateAsync("info.connection", { val: true, ack: true });
|
|
160
|
+
// Update each system
|
|
161
|
+
for (const system of systems) {
|
|
162
|
+
const stats = statsMap.get(system.id);
|
|
163
|
+
const sysContainers = containers.filter((c) => c.system === system.id);
|
|
164
|
+
await this.stateManager.updateSystem(system, stats, sysContainers, config);
|
|
165
|
+
}
|
|
166
|
+
// Cleanup stale systems
|
|
167
|
+
await this.stateManager.cleanupSystems(systems.map((s) => s.name));
|
|
168
|
+
this.log.debug(`Polled ${systems.length} systems successfully`);
|
|
169
|
+
}
|
|
170
|
+
catch (err) {
|
|
171
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
172
|
+
this.log.error(`Poll failed: ${errMsg}`);
|
|
173
|
+
// On 401, invalidate token so next poll re-authenticates
|
|
174
|
+
if (err instanceof Error &&
|
|
175
|
+
err.code === "UNAUTHORIZED") {
|
|
176
|
+
this.client?.invalidateToken();
|
|
177
|
+
}
|
|
178
|
+
await this.setStateAsync("info.connection", { val: false, ack: true });
|
|
179
|
+
}
|
|
180
|
+
finally {
|
|
181
|
+
this.isPolling = false;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (require.main !== module) {
|
|
186
|
+
// Export the constructor in compact mode
|
|
187
|
+
module.exports = (options) => new BeszelAdapter(options);
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
(() => new BeszelAdapter())();
|
|
191
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import config from "@iobroker/eslint-config";
|
|
2
|
+
|
|
3
|
+
export default [
|
|
4
|
+
...config,
|
|
5
|
+
{
|
|
6
|
+
languageOptions: {
|
|
7
|
+
parserOptions: {
|
|
8
|
+
projectService: { allowDefaultProject: ["*.mjs"] },
|
|
9
|
+
tsconfigRootDir: import.meta.dirname,
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
// Test files use Mocha globals
|
|
15
|
+
files: ["test/**/*.js"],
|
|
16
|
+
languageOptions: {
|
|
17
|
+
globals: {
|
|
18
|
+
describe: "readonly",
|
|
19
|
+
it: "readonly",
|
|
20
|
+
before: "readonly",
|
|
21
|
+
after: "readonly",
|
|
22
|
+
beforeEach: "readonly",
|
|
23
|
+
afterEach: "readonly",
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
ignores: [
|
|
29
|
+
"build/**",
|
|
30
|
+
"node_modules/**",
|
|
31
|
+
"admin/**",
|
|
32
|
+
"test/**",
|
|
33
|
+
"scripts/**",
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
];
|
package/io-package.json
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
{
|
|
2
|
+
"common": {
|
|
3
|
+
"name": "beszel",
|
|
4
|
+
"version": "0.1.2",
|
|
5
|
+
"news": {
|
|
6
|
+
"0.1.2": {
|
|
7
|
+
"en": "Fix: add missing cpu_steal state to CPU breakdown metric",
|
|
8
|
+
"de": "Fix: fehlender cpu_steal Datenpunkt bei CPU Breakdown ergänzt",
|
|
9
|
+
"ru": "Исправление: добавлено отсутствующее состояние cpu_steal в разбивке CPU",
|
|
10
|
+
"pt": "Correção: adicionado estado cpu_steal ausente na métrica de detalhamento da CPU",
|
|
11
|
+
"nl": "Fix: ontbrekende cpu_steal staat toegevoegd aan CPU breakdown metric",
|
|
12
|
+
"fr": "Correction: état cpu_steal manquant ajouté à la métrique de détail CPU",
|
|
13
|
+
"it": "Fix: aggiunto lo stato cpu_steal mancante nella metrica di dettaglio CPU",
|
|
14
|
+
"es": "Corrección: agregado el estado cpu_steal faltante en la métrica de desglose CPU",
|
|
15
|
+
"pl": "Poprawka: dodano brakujący stan cpu_steal w metryce szczegółów CPU",
|
|
16
|
+
"uk": "Виправлення: додано відсутній стан cpu_steal у деталізації CPU",
|
|
17
|
+
"zh-cn": "修复:在 CPU 详细指标中添加缺失的 cpu_steal 状态"
|
|
18
|
+
},
|
|
19
|
+
"0.1.1": {
|
|
20
|
+
"en": "Fix: disabled metric states are now removed on adapter restart",
|
|
21
|
+
"de": "Fix: deaktivierte Metric-Datenpunkte werden beim Neustart gelöscht",
|
|
22
|
+
"ru": "Исправление: отключённые метрики удаляются при перезапуске",
|
|
23
|
+
"pt": "Correção: estados de métricas desativadas são removidos ao reiniciar",
|
|
24
|
+
"nl": "Fix: uitgeschakelde metrische staten worden verwijderd bij herstart",
|
|
25
|
+
"fr": "Correction: les états de métriques désactivées sont supprimés au redémarrage",
|
|
26
|
+
"it": "Fix: gli stati delle metriche disabilitate vengono rimossi al riavvio",
|
|
27
|
+
"es": "Corrección: los estados de métricas desactivadas se eliminan al reiniciar",
|
|
28
|
+
"pl": "Poprawka: wyłączone stany metryk są usuwane przy ponownym uruchomieniu",
|
|
29
|
+
"uk": "Виправлення: вимкнені стани метрик видаляються при перезапуску",
|
|
30
|
+
"zh-cn": "修复:适配器重启时删除已禁用的指标状态"
|
|
31
|
+
},
|
|
32
|
+
"0.1.0": {
|
|
33
|
+
"en": "Initial release",
|
|
34
|
+
"de": "Erstveröffentlichung",
|
|
35
|
+
"ru": "Первый выпуск",
|
|
36
|
+
"pt": "Lançamento inicial",
|
|
37
|
+
"nl": "Eerste release",
|
|
38
|
+
"fr": "Première version",
|
|
39
|
+
"it": "Prima versione",
|
|
40
|
+
"es": "Versión inicial",
|
|
41
|
+
"pl": "Pierwsze wydanie",
|
|
42
|
+
"uk": "Перший випуск",
|
|
43
|
+
"zh-cn": "初始版本"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"titleLang": {
|
|
47
|
+
"en": "Beszel Monitor",
|
|
48
|
+
"de": "Beszel Monitor",
|
|
49
|
+
"ru": "Монитор Beszel",
|
|
50
|
+
"pt": "Monitor Beszel",
|
|
51
|
+
"nl": "Beszel Monitor",
|
|
52
|
+
"fr": "Moniteur Beszel",
|
|
53
|
+
"it": "Monitor Beszel",
|
|
54
|
+
"es": "Monitor Beszel",
|
|
55
|
+
"pl": "Monitor Beszel",
|
|
56
|
+
"uk": "Монітор Beszel",
|
|
57
|
+
"zh-cn": "Beszel 监控"
|
|
58
|
+
},
|
|
59
|
+
"desc": {
|
|
60
|
+
"en": "Connects to a Beszel Hub and exposes server metrics as ioBroker states",
|
|
61
|
+
"de": "Verbindet sich mit einem Beszel Hub und stellt Server-Metriken als ioBroker-Datenpunkte bereit",
|
|
62
|
+
"ru": "Подключается к Beszel Hub и предоставляет метрики сервера как состояния ioBroker",
|
|
63
|
+
"pt": "Conecta-se a um Beszel Hub e expõe métricas do servidor como estados ioBroker",
|
|
64
|
+
"nl": "Verbindt met een Beszel Hub en stelt servermetrisch beschikbaar als ioBroker-staten",
|
|
65
|
+
"fr": "Se connecte à un Beszel Hub et expose les métriques du serveur comme états ioBroker",
|
|
66
|
+
"it": "Si connette a un Beszel Hub ed espone le metriche del server come stati ioBroker",
|
|
67
|
+
"es": "Se conecta a un Beszel Hub y expone métricas del servidor como estados ioBroker",
|
|
68
|
+
"pl": "Łączy się z Beszel Hub i udostępnia metryki serwera jako stany ioBroker",
|
|
69
|
+
"uk": "Підключається до Beszel Hub та надає метрики сервера як стани ioBroker",
|
|
70
|
+
"zh-cn": "连接到 Beszel Hub 并将服务器指标作为 ioBroker 状态公开"
|
|
71
|
+
},
|
|
72
|
+
"authors": [
|
|
73
|
+
"krobi <krobi@power-dreams.com>"
|
|
74
|
+
],
|
|
75
|
+
"licenseInformation": {
|
|
76
|
+
"license": "MIT",
|
|
77
|
+
"type": "free"
|
|
78
|
+
},
|
|
79
|
+
"platform": "Javascript/Node.js",
|
|
80
|
+
"icon": "beszel.svg",
|
|
81
|
+
"extIcon": "https://raw.githubusercontent.com/krobipd/iobroker.beszel/main/admin/beszel.svg",
|
|
82
|
+
"readme": "https://github.com/krobipd/iobroker.beszel/blob/main/README.md",
|
|
83
|
+
"enabled": true,
|
|
84
|
+
"tier": 3,
|
|
85
|
+
"loglevel": "info",
|
|
86
|
+
"mode": "daemon",
|
|
87
|
+
"type": "monitoring",
|
|
88
|
+
"compact": true,
|
|
89
|
+
"connectionType": "local",
|
|
90
|
+
"dataSource": "poll",
|
|
91
|
+
"adminUI": {
|
|
92
|
+
"config": "json"
|
|
93
|
+
},
|
|
94
|
+
"supportedMessages": {
|
|
95
|
+
"stopInstance": true,
|
|
96
|
+
"checkConnection": true
|
|
97
|
+
},
|
|
98
|
+
"dependencies": [
|
|
99
|
+
{
|
|
100
|
+
"js-controller": ">=7.0.0"
|
|
101
|
+
}
|
|
102
|
+
],
|
|
103
|
+
"globalDependencies": [
|
|
104
|
+
{
|
|
105
|
+
"admin": ">=7.6.20"
|
|
106
|
+
}
|
|
107
|
+
],
|
|
108
|
+
"instanceObjects": [
|
|
109
|
+
{
|
|
110
|
+
"_id": "info",
|
|
111
|
+
"type": "channel",
|
|
112
|
+
"common": {
|
|
113
|
+
"name": "Information"
|
|
114
|
+
},
|
|
115
|
+
"native": {}
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"_id": "info.connection",
|
|
119
|
+
"type": "state",
|
|
120
|
+
"common": {
|
|
121
|
+
"name": "Connection status",
|
|
122
|
+
"type": "boolean",
|
|
123
|
+
"role": "indicator.connected",
|
|
124
|
+
"read": true,
|
|
125
|
+
"write": false,
|
|
126
|
+
"def": false
|
|
127
|
+
},
|
|
128
|
+
"native": {}
|
|
129
|
+
}
|
|
130
|
+
]
|
|
131
|
+
},
|
|
132
|
+
"encryptedNative": [
|
|
133
|
+
"password"
|
|
134
|
+
],
|
|
135
|
+
"protectedNative": [
|
|
136
|
+
"password"
|
|
137
|
+
],
|
|
138
|
+
"native": {
|
|
139
|
+
"url": "",
|
|
140
|
+
"username": "",
|
|
141
|
+
"password": "",
|
|
142
|
+
"pollInterval": 60,
|
|
143
|
+
"metrics_uptime": true,
|
|
144
|
+
"metrics_agentVersion": false,
|
|
145
|
+
"metrics_services": false,
|
|
146
|
+
"metrics_cpu": true,
|
|
147
|
+
"metrics_loadAvg": true,
|
|
148
|
+
"metrics_cpuBreakdown": false,
|
|
149
|
+
"metrics_memory": true,
|
|
150
|
+
"metrics_memoryDetails": false,
|
|
151
|
+
"metrics_swap": false,
|
|
152
|
+
"metrics_disk": true,
|
|
153
|
+
"metrics_diskSpeed": true,
|
|
154
|
+
"metrics_extraFs": false,
|
|
155
|
+
"metrics_network": true,
|
|
156
|
+
"metrics_temperature": true,
|
|
157
|
+
"metrics_temperatureDetails": false,
|
|
158
|
+
"metrics_gpu": false,
|
|
159
|
+
"metrics_containers": false,
|
|
160
|
+
"metrics_battery": false
|
|
161
|
+
}
|
|
162
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "iobroker.beszel",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "ioBroker adapter for Beszel server monitoring",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "krobi",
|
|
7
|
+
"email": "krobi@power-dreams.com"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/krobipd/iobroker.beszel",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"ioBroker",
|
|
13
|
+
"beszel",
|
|
14
|
+
"monitoring",
|
|
15
|
+
"server",
|
|
16
|
+
"metrics"
|
|
17
|
+
],
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/krobipd/iobroker.beszel.git"
|
|
21
|
+
},
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=20.0.0"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@iobroker/adapter-core": "^3.2.3"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@iobroker/build-tools": "^3.0.1",
|
|
30
|
+
"@iobroker/eslint-config": "^1.0.0",
|
|
31
|
+
"@iobroker/testing": "^4.1.3",
|
|
32
|
+
"@types/node": "^22.0.0",
|
|
33
|
+
"mocha": "^11.0.0",
|
|
34
|
+
"source-map-support": "^0.5.21",
|
|
35
|
+
"ts-node": "^10.9.2",
|
|
36
|
+
"typescript": "^5.6.3"
|
|
37
|
+
},
|
|
38
|
+
"main": "build/main.js",
|
|
39
|
+
"scripts": {
|
|
40
|
+
"prebuild": "rm -rf ./build",
|
|
41
|
+
"build:ts": "tsc -p tsconfig.build.json",
|
|
42
|
+
"build": "npm run build:ts",
|
|
43
|
+
"build:test": "tsc -p tsconfig.test.json",
|
|
44
|
+
"watch": "tsc -w",
|
|
45
|
+
"check": "tsc --noEmit",
|
|
46
|
+
"test:package": "npm run build:test && mocha --exit \"build/test/testPackageFiles.js\"",
|
|
47
|
+
"test:integration": "npm run build:test && mocha --exit \"build/test/**/*.js\"",
|
|
48
|
+
"test": "npm run build:test && mocha --exit \"build/test/**/*.js\"",
|
|
49
|
+
"test:ci": "npm run build:test && mocha --exit --reporter spec \"build/test/**/*.js\"",
|
|
50
|
+
"lint": "eslint",
|
|
51
|
+
"lint:fix": "eslint --fix",
|
|
52
|
+
"prepare": "npm run build",
|
|
53
|
+
"version:patch": "node scripts/version.js patch",
|
|
54
|
+
"version:minor": "node scripts/version.js minor",
|
|
55
|
+
"version:major": "node scripts/version.js major"
|
|
56
|
+
},
|
|
57
|
+
"bugs": {
|
|
58
|
+
"url": "https://github.com/krobipd/iobroker.beszel/issues"
|
|
59
|
+
},
|
|
60
|
+
"readmeFilename": "README.md"
|
|
61
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const { execSync } = require('child_process');
|
|
3
|
+
|
|
4
|
+
const type = process.argv[2] || 'patch';
|
|
5
|
+
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
|
|
6
|
+
const ioPkg = JSON.parse(fs.readFileSync('io-package.json', 'utf8'));
|
|
7
|
+
|
|
8
|
+
// Version erhöhen
|
|
9
|
+
const [major, minor, patch] = pkg.version.split('.').map(Number);
|
|
10
|
+
const newVersion = type === 'major' ? `${major + 1}.0.0`
|
|
11
|
+
: type === 'minor' ? `${major}.${minor + 1}.0`
|
|
12
|
+
: `${major}.${minor}.${patch + 1}`;
|
|
13
|
+
|
|
14
|
+
console.log(`Bumping version: ${pkg.version} -> ${newVersion}`);
|
|
15
|
+
|
|
16
|
+
// Dateien aktualisieren
|
|
17
|
+
pkg.version = newVersion;
|
|
18
|
+
ioPkg.common.version = newVersion;
|
|
19
|
+
|
|
20
|
+
fs.writeFileSync('package.json', JSON.stringify(pkg, null, '\t') + '\n');
|
|
21
|
+
fs.writeFileSync('io-package.json', JSON.stringify(ioPkg, null, '\t') + '\n');
|
|
22
|
+
|
|
23
|
+
// Git Commit und Tag
|
|
24
|
+
execSync(`git add package.json io-package.json`);
|
|
25
|
+
execSync(`git commit -m "chore: bump version to ${newVersion}"`);
|
|
26
|
+
execSync(`git tag v${newVersion}`);
|
|
27
|
+
|
|
28
|
+
console.log(`\nTo push: git push && git push origin v${newVersion}`);
|