iobroker.autism-support 0.2.2 → 0.2.5
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/README.md +3 -0
- package/build/main.js +52 -9
- package/build/main.js.map +2 -2
- package/io-package.json +40 -40
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -92,6 +92,9 @@ npm run start
|
|
|
92
92
|
|
|
93
93
|
See [CHANGELOG_OLD.md](CHANGELOG_OLD.md) for older entries.
|
|
94
94
|
|
|
95
|
+
### 0.2.4
|
|
96
|
+
- Fix instance config path: `extendForeignObjectAsync` for `system.adapter.*` (removes invalid object under instance namespace)
|
|
97
|
+
|
|
95
98
|
### 0.2.2
|
|
96
99
|
- Fix object structure for latest-repo review: `timer` channel, `value.interval` roles, button `read: false`
|
|
97
100
|
|
package/build/main.js
CHANGED
|
@@ -29,6 +29,12 @@ var import_pictogram_library = require("./lib/pictogram-library");
|
|
|
29
29
|
var import_weekly_plan = require("./lib/weekly-plan");
|
|
30
30
|
const TIMER_CHANNEL = "timer";
|
|
31
31
|
const SCHEDULE_CHANNEL = "schedule";
|
|
32
|
+
function instanceConfigId(namespace) {
|
|
33
|
+
return `system.adapter.${namespace}`;
|
|
34
|
+
}
|
|
35
|
+
function legacyMisplacedInstanceConfigId(namespace) {
|
|
36
|
+
return `${namespace}.system.adapter.${namespace}`;
|
|
37
|
+
}
|
|
32
38
|
function secondsToParts(totalSeconds) {
|
|
33
39
|
const safe = Math.max(0, Math.round(totalSeconds));
|
|
34
40
|
return {
|
|
@@ -58,6 +64,7 @@ class AutismSupport extends utils.Adapter {
|
|
|
58
64
|
const defaultSeconds = this.getDefaultDurationSeconds(maxHours);
|
|
59
65
|
this.dayPeriods = (0, import_day_periods.dayPeriodsFromConfig)(this.config);
|
|
60
66
|
this.weekdayColors = (0, import_weekly_plan.weekdayColorsFromConfig)(this.config);
|
|
67
|
+
await this.migrateMisplacedInstanceConfig();
|
|
61
68
|
await this.createTimerStates();
|
|
62
69
|
await this.ensurePictogramStore();
|
|
63
70
|
await this.syncCustomPictogramsConfig();
|
|
@@ -101,7 +108,7 @@ class AutismSupport extends utils.Adapter {
|
|
|
101
108
|
const states = {
|
|
102
109
|
duration: {
|
|
103
110
|
type: "number",
|
|
104
|
-
role: "
|
|
111
|
+
role: "level.timer",
|
|
105
112
|
name: "Timer duration (seconds)",
|
|
106
113
|
read: true,
|
|
107
114
|
write: true,
|
|
@@ -111,7 +118,7 @@ class AutismSupport extends utils.Adapter {
|
|
|
111
118
|
},
|
|
112
119
|
remaining: {
|
|
113
120
|
type: "number",
|
|
114
|
-
role: "value.
|
|
121
|
+
role: "value.timer",
|
|
115
122
|
name: "Timer remaining (seconds)",
|
|
116
123
|
read: true,
|
|
117
124
|
write: false,
|
|
@@ -119,7 +126,7 @@ class AutismSupport extends utils.Adapter {
|
|
|
119
126
|
},
|
|
120
127
|
elapsed: {
|
|
121
128
|
type: "number",
|
|
122
|
-
role: "value.
|
|
129
|
+
role: "value.timer",
|
|
123
130
|
name: "Timer elapsed (seconds)",
|
|
124
131
|
read: true,
|
|
125
132
|
write: false,
|
|
@@ -213,12 +220,48 @@ class AutismSupport extends utils.Adapter {
|
|
|
213
220
|
}
|
|
214
221
|
await this.migrateTimerStateRoles();
|
|
215
222
|
}
|
|
223
|
+
/**
|
|
224
|
+
* Earlier versions used extendObject() for system.adapter.* which ioBroker resolves
|
|
225
|
+
* relative to the instance namespace (autism-support.0.system.adapter...).
|
|
226
|
+
*/
|
|
227
|
+
async migrateMisplacedInstanceConfig() {
|
|
228
|
+
const legacyId = legacyMisplacedInstanceConfigId(this.namespace);
|
|
229
|
+
const legacy = await this.getObjectAsync(legacyId);
|
|
230
|
+
if (!(legacy == null ? void 0 : legacy.native)) {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
const native = legacy.native;
|
|
234
|
+
const patch = {};
|
|
235
|
+
if (Array.isArray(native.customPictograms)) {
|
|
236
|
+
patch.customPictograms = native.customPictograms;
|
|
237
|
+
}
|
|
238
|
+
if (Array.isArray(native.weeklyPlanRows)) {
|
|
239
|
+
patch.weeklyPlanRows = native.weeklyPlanRows;
|
|
240
|
+
}
|
|
241
|
+
if (Object.keys(patch).length) {
|
|
242
|
+
await this.extendForeignObjectAsync(instanceConfigId(this.namespace), { native: patch });
|
|
243
|
+
if (patch.customPictograms) {
|
|
244
|
+
this.config.customPictograms = patch.customPictograms;
|
|
245
|
+
}
|
|
246
|
+
if (patch.weeklyPlanRows) {
|
|
247
|
+
this.config.weeklyPlanRows = patch.weeklyPlanRows;
|
|
248
|
+
}
|
|
249
|
+
this.log.info(`Migrated instance native config from misplaced object ${legacyId}`);
|
|
250
|
+
}
|
|
251
|
+
await this.delObjectAsync(legacyId);
|
|
252
|
+
for (const folderId of [`${this.namespace}.system.adapter`, `${this.namespace}.system`]) {
|
|
253
|
+
try {
|
|
254
|
+
await this.delObjectAsync(folderId);
|
|
255
|
+
} catch {
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
216
259
|
/** Update roles/read flags on existing timer states (object-structure compliance). */
|
|
217
260
|
async migrateTimerStateRoles() {
|
|
218
261
|
const patches = {
|
|
219
|
-
duration: { role: "
|
|
220
|
-
remaining: { role: "value.
|
|
221
|
-
elapsed: { role: "value.
|
|
262
|
+
duration: { role: "level.timer" },
|
|
263
|
+
remaining: { role: "value.timer" },
|
|
264
|
+
elapsed: { role: "value.timer" },
|
|
222
265
|
start: { read: false },
|
|
223
266
|
pause: { read: false },
|
|
224
267
|
resume: { read: false },
|
|
@@ -426,7 +469,7 @@ class AutismSupport extends utils.Adapter {
|
|
|
426
469
|
}
|
|
427
470
|
async syncCustomPictogramsConfig() {
|
|
428
471
|
const rows = await this.buildCustomPictogramRows();
|
|
429
|
-
await this.
|
|
472
|
+
await this.extendForeignObjectAsync(instanceConfigId(this.namespace), {
|
|
430
473
|
native: { customPictograms: rows }
|
|
431
474
|
});
|
|
432
475
|
this.config.customPictograms = rows;
|
|
@@ -520,7 +563,7 @@ class AutismSupport extends utils.Adapter {
|
|
|
520
563
|
async syncWeeklyPlansTableToNative() {
|
|
521
564
|
const library = await this.getWeeklyPlansLibrary();
|
|
522
565
|
const rows = (0, import_weekly_plan.weeklyPlanRowsFromLibrary)(library);
|
|
523
|
-
await this.
|
|
566
|
+
await this.extendForeignObjectAsync(instanceConfigId(this.namespace), {
|
|
524
567
|
native: { weeklyPlanRows: rows }
|
|
525
568
|
});
|
|
526
569
|
this.config.weeklyPlanRows = rows;
|
|
@@ -730,7 +773,7 @@ class AutismSupport extends utils.Adapter {
|
|
|
730
773
|
if (obj.command === "syncPictogramTable") {
|
|
731
774
|
await this.ensurePictogramStore();
|
|
732
775
|
const rows = await this.buildCustomPictogramRows();
|
|
733
|
-
await this.
|
|
776
|
+
await this.extendForeignObjectAsync(instanceConfigId(this.namespace), {
|
|
734
777
|
native: { customPictograms: rows }
|
|
735
778
|
});
|
|
736
779
|
this.config.customPictograms = rows;
|
package/build/main.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/main.ts"],
|
|
4
|
-
"sourcesContent": ["/*\n * ioBroker.autism-support \u2013 Visual Countdown + Daily Schedule\n */\n\nimport * as utils from \"@iobroker/adapter-core\";\nimport { TimerManager } from \"./lib/timer-manager\";\nimport {\n\tdayPeriodsFromConfig,\n\tfindCurrentPeriod,\n\tparseTimeToMinutes,\n\ttype DayPeriodDefinition,\n} from \"./lib/day-periods\";\nimport { findCurrentItemIndex, isPlanFullyExpired, parseSchedulePlan, type SchedulePlan } from \"./lib/schedule-types\";\nimport {\n\tADAPTER_LIBRARY_FILE,\n\tPICTOGRAM_DIR,\n\tPICTOGRAM_FILE_ADAPTER,\n\tPICTOGRAM_PLACEHOLDER_FILE,\n\tLEGACY_VIS_LIBRARY_FILE,\n\temptyLibrary,\n\tisIgnoredPictogramFile,\n\tlibraryFromNativeRows,\n\tmatchesPictogramKey,\n\tmergePictogramSources,\n\tnormalizeTags,\n\tparseLibrary,\n\tpictogramPublicUrl,\n\tpictogramStoragePath,\n\tsyncCustomPictogramRows,\n\tuniquePictogramFilename,\n\ttype CustomPictogram,\n\ttype PictogramLibrary,\n} from \"./lib/pictogram-library\";\nimport {\n\tapplyWeeklyPlanRowsToLibrary,\n\tcreateEmptyWeeklyPlan,\n\tparseWeeklyPlan,\n\tparseWeeklyPlansLibrary,\n\tschedulePlansEqual,\n\tweekdayColorsFromConfig,\n\tweekdayKeyFromDate,\n\tweeklyPlanRowsFromLibrary,\n\ttype WeekdayColors,\n\ttype WeekdayKey,\n\ttype WeeklyPlanData,\n\ttype WeeklyPlansLibrary,\n} from \"./lib/weekly-plan\";\n\nconst TIMER_CHANNEL = \"timer\";\nconst SCHEDULE_CHANNEL = \"schedule\";\n\nfunction secondsToParts(totalSeconds: number): { hours: number; minutes: number } {\n\tconst safe = Math.max(0, Math.round(totalSeconds));\n\treturn {\n\t\thours: Math.floor(safe / 3600),\n\t\tminutes: Math.floor((safe % 3600) / 60),\n\t};\n}\n\nclass AutismSupport extends utils.Adapter {\n\tprivate timerManager: TimerManager | null = null;\n\tprivate scheduleTick: ioBroker.Interval | undefined | null = null;\n\tprivate dayPeriods: DayPeriodDefinition[] = [];\n\tprivate weekdayColors: WeekdayColors = weekdayColorsFromConfig({} as ioBroker.AdapterConfig);\n\tprivate lastAppliedWeekday: WeekdayKey | null = null;\n\n\tpublic constructor(options: Partial<utils.AdapterOptions> = {}) {\n\t\tsuper({\n\t\t\t...options,\n\t\t\tname: \"autism-support\",\n\t\t});\n\t\tthis.on(\"ready\", this.onReady.bind(this));\n\t\tthis.on(\"stateChange\", this.onStateChange.bind(this));\n\t\tthis.on(\"message\", this.onMessage.bind(this));\n\t\tthis.on(\"unload\", this.onUnload.bind(this));\n\t}\n\n\tprivate async onReady(): Promise<void> {\n\t\tconst maxHours = this.config.maxDurationHours ?? 24;\n\t\tconst defaultSeconds = this.getDefaultDurationSeconds(maxHours);\n\t\tthis.dayPeriods = dayPeriodsFromConfig(this.config);\n\t\tthis.weekdayColors = weekdayColorsFromConfig(this.config);\n\n\t\tawait this.createTimerStates();\n\t\tawait this.ensurePictogramStore();\n\t\tawait this.syncCustomPictogramsConfig();\n\t\tawait this.createScheduleStates();\n\t\t// Only apply Admin name/delete edits when the table already lists plans (avoid wiping on first boot).\n\t\tif (Array.isArray(this.config.weeklyPlanRows) && this.config.weeklyPlanRows.length > 0) {\n\t\t\tawait this.applyWeeklyPlanRowsFromConfig();\n\t\t}\n\t\tawait this.syncWeeklyPlansTableToNative();\n\n\t\tthis.timerManager = new TimerManager(\n\t\t\tasync snapshot => {\n\t\t\t\tawait this.publishTimerSnapshot(snapshot);\n\t\t\t},\n\t\t\t{\n\t\t\t\tsetInterval: (handler, ms) => this.setInterval(handler, ms),\n\t\t\t\tclearInterval: handle => this.clearInterval(handle as ioBroker.Interval),\n\t\t\t},\n\t\t);\n\n\t\tawait this.timerManager.setDuration(defaultSeconds, maxHours);\n\t\tawait this.publishTimerSnapshot(this.timerManager.getSnapshot());\n\t\tawait this.publishScheduleRuntime();\n\n\t\tthis.subscribeStates(`${this.namespace}.${TIMER_CHANNEL}.*`);\n\t\tthis.subscribeStates(`${this.namespace}.${SCHEDULE_CHANNEL}.*`);\n\n\t\tthis.scheduleTick = this.setInterval(() => {\n\t\t\tvoid this.publishScheduleRuntime();\n\t\t}, 30_000);\n\n\t\tthis.log.info(\"Autism Support adapter ready \u2013 Visual Countdown + Weekly Schedule\");\n\t}\n\n\tprivate getDefaultDurationSeconds(maxHours: number): number {\n\t\tconst hours = Math.min(maxHours, Math.max(0, this.config.defaultDurationHours ?? 1));\n\t\tconst minutes = Math.min(59, Math.max(0, this.config.defaultDurationMinutes ?? 0));\n\t\tconst total = hours * 3600 + minutes * 60;\n\t\treturn Math.max(60, Math.min(maxHours * 3600, total));\n\t}\n\n\tprivate async createTimerStates(): Promise<void> {\n\t\tawait this.setObjectNotExistsAsync(TIMER_CHANNEL, {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: \"Visual Countdown\" },\n\t\t\tnative: {},\n\t\t});\n\n\t\tconst states: Record<\n\t\t\tstring,\n\t\t\t{\n\t\t\t\ttype: \"number\" | \"boolean\";\n\t\t\t\trole: string;\n\t\t\t\tname: string;\n\t\t\t\tread: boolean;\n\t\t\t\twrite: boolean;\n\t\t\t\tunit?: string;\n\t\t\t\tmin?: number;\n\t\t\t\tmax?: number;\n\t\t\t}\n\t\t> = {\n\t\t\tduration: {\n\t\t\t\ttype: \"number\",\n\t\t\t\trole: \"value.interval\",\n\t\t\t\tname: \"Timer duration (seconds)\",\n\t\t\t\tread: true,\n\t\t\t\twrite: true,\n\t\t\t\tunit: \"s\",\n\t\t\t\tmin: 60,\n\t\t\t\tmax: 86400,\n\t\t\t},\n\t\t\tremaining: {\n\t\t\t\ttype: \"number\",\n\t\t\t\trole: \"value.interval\",\n\t\t\t\tname: \"Timer remaining (seconds)\",\n\t\t\t\tread: true,\n\t\t\t\twrite: false,\n\t\t\t\tunit: \"s\",\n\t\t\t},\n\t\t\telapsed: {\n\t\t\t\ttype: \"number\",\n\t\t\t\trole: \"value.interval\",\n\t\t\t\tname: \"Timer elapsed (seconds)\",\n\t\t\t\tread: true,\n\t\t\t\twrite: false,\n\t\t\t\tunit: \"s\",\n\t\t\t},\n\t\t\trunning: {\n\t\t\t\ttype: \"boolean\",\n\t\t\t\trole: \"indicator\",\n\t\t\t\tname: \"Timer running\",\n\t\t\t\tread: true,\n\t\t\t\twrite: false,\n\t\t\t},\n\t\t\tpaused: {\n\t\t\t\ttype: \"boolean\",\n\t\t\t\trole: \"indicator\",\n\t\t\t\tname: \"Timer paused\",\n\t\t\t\tread: true,\n\t\t\t\twrite: false,\n\t\t\t},\n\t\t\tfinished: {\n\t\t\t\ttype: \"boolean\",\n\t\t\t\trole: \"indicator\",\n\t\t\t\tname: \"Timer finished\",\n\t\t\t\tread: true,\n\t\t\t\twrite: false,\n\t\t\t},\n\t\t\tstart: {\n\t\t\t\ttype: \"boolean\",\n\t\t\t\trole: \"button.start\",\n\t\t\t\tname: \"Start timer\",\n\t\t\t\tread: false,\n\t\t\t\twrite: true,\n\t\t\t},\n\t\t\tpause: {\n\t\t\t\ttype: \"boolean\",\n\t\t\t\trole: \"button.pause\",\n\t\t\t\tname: \"Pause timer\",\n\t\t\t\tread: false,\n\t\t\t\twrite: true,\n\t\t\t},\n\t\t\tresume: {\n\t\t\t\ttype: \"boolean\",\n\t\t\t\trole: \"button.start\",\n\t\t\t\tname: \"Resume timer\",\n\t\t\t\tread: false,\n\t\t\t\twrite: true,\n\t\t\t},\n\t\t\tstop: {\n\t\t\t\ttype: \"boolean\",\n\t\t\t\trole: \"button.stop\",\n\t\t\t\tname: \"Stop timer\",\n\t\t\t\tread: false,\n\t\t\t\twrite: true,\n\t\t\t},\n\t\t\tsetDurationHours: {\n\t\t\t\ttype: \"number\",\n\t\t\t\trole: \"level\",\n\t\t\t\tname: \"Set timer duration (hours)\",\n\t\t\t\tread: true,\n\t\t\t\twrite: true,\n\t\t\t\tunit: \"h\",\n\t\t\t\tmin: 0,\n\t\t\t\tmax: 24,\n\t\t\t},\n\t\t\tsetDurationMinutes: {\n\t\t\t\ttype: \"number\",\n\t\t\t\trole: \"level\",\n\t\t\t\tname: \"Set timer duration (minutes)\",\n\t\t\t\tread: true,\n\t\t\t\twrite: true,\n\t\t\t\tunit: \"min\",\n\t\t\t\tmin: 0,\n\t\t\t\tmax: 59,\n\t\t\t},\n\t\t};\n\n\t\tfor (const [id, def] of Object.entries(states)) {\n\t\t\tawait this.setObjectNotExistsAsync(`${TIMER_CHANNEL}.${id}`, {\n\t\t\t\ttype: \"state\",\n\t\t\t\tcommon: {\n\t\t\t\t\tname: def.name,\n\t\t\t\t\ttype: def.type,\n\t\t\t\t\trole: def.role,\n\t\t\t\t\tread: def.read,\n\t\t\t\t\twrite: def.write,\n\t\t\t\t\tunit: def.unit,\n\t\t\t\t\tmin: def.min,\n\t\t\t\t\tmax: def.max,\n\t\t\t\t},\n\t\t\t\tnative: {},\n\t\t\t});\n\t\t}\n\n\t\tawait this.migrateTimerStateRoles();\n\t}\n\n\t/** Update roles/read flags on existing timer states (object-structure compliance). */\n\tprivate async migrateTimerStateRoles(): Promise<void> {\n\t\tconst patches: Record<string, { role?: string; read?: boolean }> = {\n\t\t\tduration: { role: \"value.interval\" },\n\t\t\tremaining: { role: \"value.interval\" },\n\t\t\telapsed: { role: \"value.interval\" },\n\t\t\tstart: { read: false },\n\t\t\tpause: { read: false },\n\t\t\tresume: { read: false },\n\t\t\tstop: { read: false },\n\t\t};\n\t\tfor (const [id, patch] of Object.entries(patches)) {\n\t\t\tconst common: Partial<ioBroker.StateCommon> = {};\n\t\t\tif (patch.role) {\n\t\t\t\tcommon.role = patch.role;\n\t\t\t}\n\t\t\tif (patch.read !== undefined) {\n\t\t\t\tcommon.read = patch.read;\n\t\t\t}\n\t\t\tawait this.extendObjectAsync(`${TIMER_CHANNEL}.${id}`, { common });\n\t\t}\n\t}\n\n\tprivate async createScheduleStates(): Promise<void> {\n\t\tawait this.setObjectNotExistsAsync(SCHEDULE_CHANNEL, {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: \"Daily schedule\" },\n\t\t\tnative: {},\n\t\t});\n\n\t\tawait this.setObjectNotExistsAsync(`${SCHEDULE_CHANNEL}.plan`, {\n\t\t\ttype: \"state\",\n\t\t\tcommon: {\n\t\t\t\tname: \"Schedule plan (JSON)\",\n\t\t\t\ttype: \"string\",\n\t\t\t\trole: \"json\",\n\t\t\t\tread: true,\n\t\t\t\twrite: true,\n\t\t\t\tdef: JSON.stringify({ version: 1, items: [] }),\n\t\t\t},\n\t\t\tnative: {},\n\t\t});\n\n\t\tawait this.setObjectNotExistsAsync(`${SCHEDULE_CHANNEL}.periods`, {\n\t\t\ttype: \"state\",\n\t\t\tcommon: {\n\t\t\t\tname: \"Day periods from admin (JSON)\",\n\t\t\t\ttype: \"string\",\n\t\t\t\trole: \"json\",\n\t\t\t\tread: true,\n\t\t\t\twrite: false,\n\t\t\t},\n\t\t\tnative: {},\n\t\t});\n\n\t\tawait this.setObjectNotExistsAsync(`${SCHEDULE_CHANNEL}.periodOverrides`, {\n\t\t\ttype: \"state\",\n\t\t\tcommon: {\n\t\t\t\tname: \"Day period on/off overrides from schedule config (JSON)\",\n\t\t\t\ttype: \"string\",\n\t\t\t\trole: \"json\",\n\t\t\t\tread: true,\n\t\t\t\twrite: true,\n\t\t\t\tdef: \"{}\",\n\t\t\t},\n\t\t\tnative: {},\n\t\t});\n\n\t\tawait this.setObjectNotExistsAsync(`${SCHEDULE_CHANNEL}.nowMinutes`, {\n\t\t\ttype: \"state\",\n\t\t\tcommon: {\n\t\t\t\tname: \"Minutes since midnight (local)\",\n\t\t\t\ttype: \"number\",\n\t\t\t\trole: \"value\",\n\t\t\t\tread: true,\n\t\t\t\twrite: false,\n\t\t\t\tunit: \"min\",\n\t\t\t\tmin: 0,\n\t\t\t\tmax: 1439,\n\t\t\t},\n\t\t\tnative: {},\n\t\t});\n\n\t\tawait this.setObjectNotExistsAsync(`${SCHEDULE_CHANNEL}.currentPeriod`, {\n\t\t\ttype: \"state\",\n\t\t\tcommon: {\n\t\t\t\tname: \"Current day period id\",\n\t\t\t\ttype: \"string\",\n\t\t\t\trole: \"text\",\n\t\t\t\tread: true,\n\t\t\t\twrite: false,\n\t\t\t},\n\t\t\tnative: {},\n\t\t});\n\n\t\tawait this.setObjectNotExistsAsync(`${SCHEDULE_CHANNEL}.currentItemIndex`, {\n\t\t\ttype: \"state\",\n\t\t\tcommon: {\n\t\t\t\tname: \"Index of active schedule item (-1 = none)\",\n\t\t\t\ttype: \"number\",\n\t\t\t\trole: \"value\",\n\t\t\t\tread: true,\n\t\t\t\twrite: false,\n\t\t\t\tmin: -1,\n\t\t\t},\n\t\t\tnative: {},\n\t\t});\n\n\t\tawait this.setObjectNotExistsAsync(`${SCHEDULE_CHANNEL}.clearAfterLast`, {\n\t\t\ttype: \"state\",\n\t\t\tcommon: {\n\t\t\t\tname: \"Clear plan automatically after last pictogram ends\",\n\t\t\t\ttype: \"boolean\",\n\t\t\t\trole: \"switch\",\n\t\t\t\tread: true,\n\t\t\t\twrite: true,\n\t\t\t\tdef: false,\n\t\t\t},\n\t\t\tnative: {},\n\t\t});\n\n\t\tawait this.setObjectNotExistsAsync(`${SCHEDULE_CHANNEL}.pictogramLibrary`, {\n\t\t\ttype: \"state\",\n\t\t\tcommon: {\n\t\t\t\tname: \"Custom pictogram library (JSON)\",\n\t\t\t\ttype: \"string\",\n\t\t\t\trole: \"json\",\n\t\t\t\tread: true,\n\t\t\t\twrite: false,\n\t\t\t},\n\t\t\tnative: {},\n\t\t});\n\n\t\tawait this.setObjectNotExistsAsync(`${SCHEDULE_CHANNEL}.weeklyPlan`, {\n\t\t\ttype: \"state\",\n\t\t\tcommon: {\n\t\t\t\tname: \"Active weekly plan (JSON, Mon\u2013Sun)\",\n\t\t\t\ttype: \"string\",\n\t\t\t\trole: \"json\",\n\t\t\t\tread: true,\n\t\t\t\twrite: true,\n\t\t\t\tdef: JSON.stringify(createEmptyWeeklyPlan()),\n\t\t\t},\n\t\t\tnative: {},\n\t\t});\n\n\t\tawait this.setObjectNotExistsAsync(`${SCHEDULE_CHANNEL}.weeklyPlansLibrary`, {\n\t\t\ttype: \"state\",\n\t\t\tcommon: {\n\t\t\t\tname: \"Saved weekly plans library (JSON)\",\n\t\t\t\ttype: \"string\",\n\t\t\t\trole: \"json\",\n\t\t\t\tread: true,\n\t\t\t\twrite: true,\n\t\t\t\tdef: JSON.stringify({ version: 1, activeId: null, plans: [] }),\n\t\t\t},\n\t\t\tnative: {},\n\t\t});\n\n\t\tawait this.setObjectNotExistsAsync(`${SCHEDULE_CHANNEL}.loadDailyFromWeekly`, {\n\t\t\ttype: \"state\",\n\t\t\tcommon: {\n\t\t\t\tname: \"Load daily plan from active weekly plan each day\",\n\t\t\t\ttype: \"boolean\",\n\t\t\t\trole: \"switch\",\n\t\t\t\tread: true,\n\t\t\t\twrite: true,\n\t\t\t\tdef: false,\n\t\t\t},\n\t\t\tnative: {},\n\t\t});\n\n\t\tawait this.setObjectNotExistsAsync(`${SCHEDULE_CHANNEL}.weekdayColors`, {\n\t\t\ttype: \"state\",\n\t\t\tcommon: {\n\t\t\t\tname: \"Weekday background colors from admin (JSON)\",\n\t\t\t\ttype: \"string\",\n\t\t\t\trole: \"json\",\n\t\t\t\tread: true,\n\t\t\t\twrite: false,\n\t\t\t},\n\t\t\tnative: {},\n\t\t});\n\n\t\tconst planState = await this.getStateAsync(`${SCHEDULE_CHANNEL}.plan`);\n\t\tif (planState?.val == null || planState.val === \"\") {\n\t\t\tawait this.setState(`${SCHEDULE_CHANNEL}.plan`, JSON.stringify({ version: 1, items: [] }), true);\n\t\t}\n\t\tconst overridesState = await this.getStateAsync(`${SCHEDULE_CHANNEL}.periodOverrides`);\n\t\tif (overridesState?.val == null || overridesState.val === \"\") {\n\t\t\tawait this.setState(`${SCHEDULE_CHANNEL}.periodOverrides`, \"{}\", true);\n\t\t}\n\t\tconst clearAfterState = await this.getStateAsync(`${SCHEDULE_CHANNEL}.clearAfterLast`);\n\t\tif (clearAfterState?.val == null) {\n\t\t\tawait this.setState(`${SCHEDULE_CHANNEL}.clearAfterLast`, false, true);\n\t\t}\n\t\tconst loadDailyState = await this.getStateAsync(`${SCHEDULE_CHANNEL}.loadDailyFromWeekly`);\n\t\tif (loadDailyState?.val == null) {\n\t\t\tawait this.setState(`${SCHEDULE_CHANNEL}.loadDailyFromWeekly`, false, true);\n\t\t}\n\n\t\tconst weeklyState = await this.getStateAsync(`${SCHEDULE_CHANNEL}.weeklyPlan`);\n\t\tif (weeklyState?.val == null || weeklyState.val === \"\") {\n\t\t\tconst seed = parseSchedulePlan(planState?.val);\n\t\t\tawait this.setState(\n\t\t\t\t`${SCHEDULE_CHANNEL}.weeklyPlan`,\n\t\t\t\tJSON.stringify(createEmptyWeeklyPlan(seed.items.length ? seed : undefined)),\n\t\t\t\ttrue,\n\t\t\t);\n\t\t}\n\t\tconst libraryState = await this.getStateAsync(`${SCHEDULE_CHANNEL}.weeklyPlansLibrary`);\n\t\tif (libraryState?.val == null || libraryState.val === \"\") {\n\t\t\tawait this.setState(\n\t\t\t\t`${SCHEDULE_CHANNEL}.weeklyPlansLibrary`,\n\t\t\t\tJSON.stringify({ version: 1, activeId: null, plans: [] }),\n\t\t\t\ttrue,\n\t\t\t);\n\t\t}\n\n\t\t// Publish admin period definitions once at start (times/colors); overrides stay separate.\n\t\tawait this.setState(`${SCHEDULE_CHANNEL}.periods`, JSON.stringify(this.dayPeriods), true);\n\t\tawait this.setState(`${SCHEDULE_CHANNEL}.weekdayColors`, JSON.stringify(this.weekdayColors), true);\n\t\tawait this.publishPictogramLibrary();\n\t}\n\n\tprivate async buildCustomPictogramRows(): Promise<Array<{ file: string; label: string; tags: string }>> {\n\t\tconst files = await this.listPictogramFiles();\n\t\treturn syncCustomPictogramRows(files || [], this.config.customPictograms);\n\t}\n\n\tprivate async syncCustomPictogramsConfig(): Promise<void> {\n\t\tconst rows = await this.buildCustomPictogramRows();\n\t\tawait this.extendObject(`system.adapter.${this.namespace}`, {\n\t\t\tnative: { customPictograms: rows },\n\t\t});\n\t\tthis.config.customPictograms = rows;\n\t\tawait this.publishPictogramLibrary();\n\t}\n\n\tprivate async ensurePictogramStore(): Promise<void> {\n\t\ttry {\n\t\t\tawait this.readFileAsync(this.namespace, ADAPTER_LIBRARY_FILE);\n\t\t} catch {\n\t\t\ttry {\n\t\t\t\tawait this.writeFileAsync(\n\t\t\t\t\tthis.namespace,\n\t\t\t\t\tADAPTER_LIBRARY_FILE,\n\t\t\t\t\tJSON.stringify(emptyLibrary(), null, 2),\n\t\t\t\t);\n\t\t\t\tthis.log.info(`Created adapter pictogram library ${this.namespace}/${ADAPTER_LIBRARY_FILE}`);\n\t\t\t} catch (error) {\n\t\t\t\tthis.log.error(`Could not create adapter pictogram library: ${(error as Error).message}`);\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\tconst legacy = await this.readFileAsync(PICTOGRAM_FILE_ADAPTER, LEGACY_VIS_LIBRARY_FILE);\n\t\t\tconst raw = typeof legacy.file === \"string\" ? legacy.file : Buffer.from(legacy.file).toString(\"utf8\");\n\t\t\tconst migrated = parseLibrary(raw);\n\t\t\tif (migrated.items.length) {\n\t\t\t\tawait this.writeFileAsync(this.namespace, ADAPTER_LIBRARY_FILE, JSON.stringify(migrated, null, 2));\n\t\t\t\tthis.log.info(`Migrated pictogram library from vis-2 to ${this.namespace}`);\n\t\t\t}\n\t\t} catch {\n\t\t\t// no legacy library in vis-2\n\t\t}\n\n\t\ttry {\n\t\t\tawait this.unlinkAsync(PICTOGRAM_FILE_ADAPTER, LEGACY_VIS_LIBRARY_FILE);\n\t\t} catch {\n\t\t\t// ignore\n\t\t}\n\n\t\ttry {\n\t\t\tconst hint =\n\t\t\t\t\"Piktogramm-Bilder (PNG, JPEG, GIF, WebP, SVG) hier hochladen.\\n\" +\n\t\t\t\t\"Keine neuen Ordner anlegen (Dateimanager zeigt dann oft \u201Edoppelter Name\u201C).\\n\" +\n\t\t\t\t\"Stattdessen oben auf Hochladen klicken und Bilder in DIESEN Ordner legen.\\n\";\n\t\t\tawait this.writeFileAsync(PICTOGRAM_FILE_ADAPTER, `${PICTOGRAM_DIR}/${PICTOGRAM_PLACEHOLDER_FILE}`, hint);\n\t\t\tthis.log.info(`Ensured vis-2 pictogram folder ${PICTOGRAM_FILE_ADAPTER}/${PICTOGRAM_DIR}`);\n\t\t} catch (error) {\n\t\t\tthis.log.error(\n\t\t\t\t`Could not write ${PICTOGRAM_FILE_ADAPTER}/${PICTOGRAM_DIR}/${PICTOGRAM_PLACEHOLDER_FILE}: ${(error as Error).message}`,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate async getPublishedPictogramLibrary(): Promise<PictogramLibrary> {\n\t\treturn mergePictogramSources(\n\t\t\tawait this.getMergedPictogramLibrary(),\n\t\t\tlibraryFromNativeRows(this.config.customPictograms),\n\t\t);\n\t}\n\n\tprivate async publishPictogramLibrary(): Promise<void> {\n\t\tconst library = await this.getPublishedPictogramLibrary();\n\t\tawait this.setState(`${SCHEDULE_CHANNEL}.pictogramLibrary`, JSON.stringify(library), true);\n\t}\n\n\tprivate async publishTimerSnapshot(snapshot: {\n\t\tduration: number;\n\t\tremaining: number;\n\t\telapsed: number;\n\t\trunning: boolean;\n\t\tpaused: boolean;\n\t\tfinished: boolean;\n\t}): Promise<void> {\n\t\tawait this.setState(`${TIMER_CHANNEL}.duration`, snapshot.duration, true);\n\t\tawait this.setState(`${TIMER_CHANNEL}.remaining`, snapshot.remaining, true);\n\t\tawait this.setState(`${TIMER_CHANNEL}.elapsed`, snapshot.elapsed, true);\n\t\tawait this.setState(`${TIMER_CHANNEL}.running`, snapshot.running, true);\n\t\tawait this.setState(`${TIMER_CHANNEL}.paused`, snapshot.paused, true);\n\t\tawait this.setState(`${TIMER_CHANNEL}.finished`, snapshot.finished, true);\n\t}\n\n\tprivate async getPlan(): Promise<SchedulePlan> {\n\t\tconst state = await this.getStateAsync(`${SCHEDULE_CHANNEL}.plan`);\n\t\treturn parseSchedulePlan(state?.val);\n\t}\n\n\tprivate async getPeriodOverrides(): Promise<Record<string, boolean>> {\n\t\tconst state = await this.getStateAsync(`${SCHEDULE_CHANNEL}.periodOverrides`);\n\t\ttry {\n\t\t\tconst raw = typeof state?.val === \"string\" ? JSON.parse(state.val) : state?.val;\n\t\t\treturn raw && typeof raw === \"object\" ? (raw as Record<string, boolean>) : {};\n\t\t} catch {\n\t\t\treturn {};\n\t\t}\n\t}\n\n\tprivate async getEffectivePeriods(): Promise<DayPeriodDefinition[]> {\n\t\tconst overrides = await this.getPeriodOverrides();\n\t\treturn this.dayPeriods.map(period => ({\n\t\t\t...period,\n\t\t\tenabled: overrides[period.id] === undefined ? period.enabled : Boolean(overrides[period.id]),\n\t\t}));\n\t}\n\n\tprivate async getWeeklyPlan(): Promise<WeeklyPlanData> {\n\t\tconst state = await this.getStateAsync(`${SCHEDULE_CHANNEL}.weeklyPlan`);\n\t\treturn parseWeeklyPlan(state?.val);\n\t}\n\n\tprivate async getWeeklyPlansLibrary(): Promise<WeeklyPlansLibrary> {\n\t\tconst state = await this.getStateAsync(`${SCHEDULE_CHANNEL}.weeklyPlansLibrary`);\n\t\treturn parseWeeklyPlansLibrary(state?.val);\n\t}\n\n\tprivate async syncWeeklyPlansTableToNative(): Promise<void> {\n\t\tconst library = await this.getWeeklyPlansLibrary();\n\t\tconst rows = weeklyPlanRowsFromLibrary(library);\n\t\tawait this.extendObject(`system.adapter.${this.namespace}`, {\n\t\t\tnative: { weeklyPlanRows: rows },\n\t\t});\n\t\tthis.config.weeklyPlanRows = rows;\n\t}\n\n\tprivate async applyWeeklyPlanRowsFromConfig(): Promise<void> {\n\t\tconst library = await this.getWeeklyPlansLibrary();\n\t\tconst next = applyWeeklyPlanRowsToLibrary(library, this.config.weeklyPlanRows);\n\t\tif (JSON.stringify(next) !== JSON.stringify(library)) {\n\t\t\tawait this.setState(`${SCHEDULE_CHANNEL}.weeklyPlansLibrary`, JSON.stringify(next), true);\n\t\t}\n\t}\n\n\tprivate async maybeApplyWeeklyToDaily(): Promise<void> {\n\t\tconst loadState = await this.getStateAsync(`${SCHEDULE_CHANNEL}.loadDailyFromWeekly`);\n\t\tif (!loadState?.val) {\n\t\t\treturn;\n\t\t}\n\t\tconst weekday = weekdayKeyFromDate(new Date());\n\t\tconst weekly = await this.getWeeklyPlan();\n\t\tconst dayPlan = weekly.days[weekday];\n\t\tconst current = await this.getPlan();\n\t\tif (this.lastAppliedWeekday === weekday && schedulePlansEqual(current, dayPlan)) {\n\t\t\treturn;\n\t\t}\n\t\tawait this.setState(`${SCHEDULE_CHANNEL}.plan`, JSON.stringify(dayPlan), true);\n\t\tthis.lastAppliedWeekday = weekday;\n\t\tthis.log.debug(`Daily plan loaded from weekly plan (${weekday})`);\n\t}\n\n\tprivate async publishScheduleRuntime(): Promise<void> {\n\t\tawait this.maybeApplyWeeklyToDaily();\n\n\t\tconst now = new Date();\n\t\tconst minutes = now.getHours() * 60 + now.getMinutes();\n\t\tconst periods = await this.getEffectivePeriods();\n\t\tconst period = findCurrentPeriod(minutes, periods);\n\t\tlet plan = await this.getPlan();\n\n\t\tconst clearAfterState = await this.getStateAsync(`${SCHEDULE_CHANNEL}.clearAfterLast`);\n\t\tconst clearAfterLast = Boolean(clearAfterState?.val);\n\t\tif (clearAfterLast && isPlanFullyExpired(plan, minutes, parseTimeToMinutes)) {\n\t\t\tplan = { version: 1, items: [] };\n\t\t\tawait this.setState(`${SCHEDULE_CHANNEL}.plan`, JSON.stringify(plan), true);\n\t\t\tthis.log.info(\"Schedule plan cleared automatically after last pictogram ended\");\n\t\t}\n\n\t\tconst itemIndex = findCurrentItemIndex(plan, minutes, parseTimeToMinutes);\n\n\t\t// Keep admin period metadata available; do not wipe Config overrides.\n\t\tawait this.setState(`${SCHEDULE_CHANNEL}.periods`, JSON.stringify(this.dayPeriods), true);\n\t\tawait this.setState(`${SCHEDULE_CHANNEL}.weekdayColors`, JSON.stringify(this.weekdayColors), true);\n\t\tawait this.setState(`${SCHEDULE_CHANNEL}.nowMinutes`, minutes, true);\n\t\tawait this.setState(`${SCHEDULE_CHANNEL}.currentPeriod`, period?.id ?? \"\", true);\n\t\tawait this.setState(`${SCHEDULE_CHANNEL}.currentItemIndex`, itemIndex, true);\n\t}\n\n\tprivate async onStateChange(id: string, state: ioBroker.State | null | undefined): Promise<void> {\n\t\tif (!state || state.ack) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (id.startsWith(`${this.namespace}.${SCHEDULE_CHANNEL}.`)) {\n\t\t\tconst localId = id.replace(`${this.namespace}.${SCHEDULE_CHANNEL}.`, \"\");\n\t\t\tif (localId === \"plan\") {\n\t\t\t\tconst plan = parseSchedulePlan(state.val);\n\t\t\t\tawait this.setState(`${SCHEDULE_CHANNEL}.plan`, JSON.stringify(plan), true);\n\t\t\t\tawait this.publishScheduleRuntime();\n\t\t\t} else if (localId === \"periodOverrides\") {\n\t\t\t\ttry {\n\t\t\t\t\tconst raw = typeof state.val === \"string\" ? JSON.parse(String(state.val)) : state.val;\n\t\t\t\t\tconst cleaned = raw && typeof raw === \"object\" ? (raw as Record<string, boolean>) : {};\n\t\t\t\t\tawait this.setState(`${SCHEDULE_CHANNEL}.periodOverrides`, JSON.stringify(cleaned), true);\n\t\t\t\t\tawait this.publishScheduleRuntime();\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthis.log.error(`Invalid periodOverrides: ${(error as Error).message}`);\n\t\t\t\t}\n\t\t\t} else if (localId === \"clearAfterLast\") {\n\t\t\t\tawait this.setState(`${SCHEDULE_CHANNEL}.clearAfterLast`, Boolean(state.val), true);\n\t\t\t\tawait this.publishScheduleRuntime();\n\t\t\t} else if (localId === \"weeklyPlan\") {\n\t\t\t\tconst weekly = parseWeeklyPlan(state.val);\n\t\t\t\tawait this.setState(`${SCHEDULE_CHANNEL}.weeklyPlan`, JSON.stringify(weekly), true);\n\t\t\t\tthis.lastAppliedWeekday = null;\n\t\t\t\tawait this.publishScheduleRuntime();\n\t\t\t} else if (localId === \"weeklyPlansLibrary\") {\n\t\t\t\tconst library = parseWeeklyPlansLibrary(state.val);\n\t\t\t\tawait this.setState(`${SCHEDULE_CHANNEL}.weeklyPlansLibrary`, JSON.stringify(library), true);\n\t\t\t\tawait this.syncWeeklyPlansTableToNative();\n\t\t\t} else if (localId === \"loadDailyFromWeekly\") {\n\t\t\t\tawait this.setState(`${SCHEDULE_CHANNEL}.loadDailyFromWeekly`, Boolean(state.val), true);\n\t\t\t\tthis.lastAppliedWeekday = null;\n\t\t\t\tawait this.publishScheduleRuntime();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this.timerManager || !id.startsWith(`${this.namespace}.${TIMER_CHANNEL}.`)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst localId = id.replace(`${this.namespace}.${TIMER_CHANNEL}.`, \"\");\n\t\tconst maxHours = this.config.maxDurationHours ?? 24;\n\n\t\ttry {\n\t\t\tswitch (localId) {\n\t\t\t\tcase \"start\":\n\t\t\t\t\tif (state.val === true) {\n\t\t\t\t\t\tawait this.timerManager.start();\n\t\t\t\t\t}\n\t\t\t\t\tawait this.setState(`${TIMER_CHANNEL}.start`, false, true);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"pause\":\n\t\t\t\t\tif (state.val === true) {\n\t\t\t\t\t\tawait this.timerManager.pause();\n\t\t\t\t\t}\n\t\t\t\t\tawait this.setState(`${TIMER_CHANNEL}.pause`, false, true);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"resume\":\n\t\t\t\t\tif (state.val === true) {\n\t\t\t\t\t\tawait this.timerManager.resume();\n\t\t\t\t\t}\n\t\t\t\t\tawait this.setState(`${TIMER_CHANNEL}.resume`, false, true);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"stop\":\n\t\t\t\t\tif (state.val === true) {\n\t\t\t\t\t\tawait this.timerManager.stop();\n\t\t\t\t\t}\n\t\t\t\t\tawait this.setState(`${TIMER_CHANNEL}.stop`, false, true);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"duration\":\n\t\t\t\t\tif (typeof state.val === \"number\") {\n\t\t\t\t\t\tawait this.timerManager.setDuration(state.val, maxHours);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"setDurationHours\":\n\t\t\t\t\tif (typeof state.val === \"number\") {\n\t\t\t\t\t\tawait this.applyDurationParts(Math.round(state.val), undefined, maxHours);\n\t\t\t\t\t}\n\t\t\t\t\tawait this.setState(`${TIMER_CHANNEL}.setDurationHours`, 0, true);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"setDurationMinutes\":\n\t\t\t\t\tif (typeof state.val === \"number\") {\n\t\t\t\t\t\tawait this.applyDurationParts(undefined, Math.round(state.val), maxHours);\n\t\t\t\t\t}\n\t\t\t\t\tawait this.setState(`${TIMER_CHANNEL}.setDurationMinutes`, 0, true);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tthis.log.error(`Timer command failed (${localId}): ${(error as Error).message}`);\n\t\t}\n\t}\n\n\tprivate reply(obj: ioBroker.Message, payload: unknown): void {\n\t\tif (obj.callback) {\n\t\t\tthis.sendTo(obj.from, obj.command, payload, obj.callback);\n\t\t}\n\t}\n\n\tprivate async loadPictogramLibrary(): Promise<PictogramLibrary> {\n\t\ttry {\n\t\t\tconst file = await this.readFileAsync(this.namespace, ADAPTER_LIBRARY_FILE);\n\t\t\tconst raw = typeof file.file === \"string\" ? file.file : Buffer.from(file.file).toString(\"utf8\");\n\t\t\treturn parseLibrary(raw);\n\t\t} catch {\n\t\t\treturn emptyLibrary();\n\t\t}\n\t}\n\n\tprivate async savePictogramLibrary(library: PictogramLibrary): Promise<void> {\n\t\tawait this.writeFileAsync(this.namespace, ADAPTER_LIBRARY_FILE, JSON.stringify(library, null, 2));\n\t\tawait this.setState(`${SCHEDULE_CHANNEL}.pictogramLibrary`, JSON.stringify(library), true);\n\t}\n\n\tprivate async listPictogramFiles(): Promise<string[] | null> {\n\t\ttry {\n\t\t\tconst result = await this.readDirAsync(PICTOGRAM_FILE_ADAPTER, PICTOGRAM_DIR);\n\t\t\treturn (result || [])\n\t\t\t\t.filter(entry => !entry.isDir && !isIgnoredPictogramFile(entry.file))\n\t\t\t\t.map(entry => entry.file);\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate async getMergedPictogramLibrary(): Promise<PictogramLibrary> {\n\t\tconst library = await this.loadPictogramLibrary();\n\t\tconst files = await this.listPictogramFiles();\n\t\tif (!files) {\n\t\t\treturn library;\n\t\t}\n\t\tconst known = new Set(library.items.map(item => item.filename));\n\t\tfor (const filename of files) {\n\t\t\tif (known.has(filename)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlibrary.items.push({\n\t\t\t\tid: filename,\n\t\t\t\tfilename,\n\t\t\t\tpath: pictogramStoragePath(filename),\n\t\t\t\tlabel: filename.replace(/\\.[^.]+$/, \"\").replace(/-\\d+$/, \"\"),\n\t\t\t\ttags: [],\n\t\t\t\toriginalName: filename,\n\t\t\t\tmime: \"\",\n\t\t\t\tuploadedAt: 0,\n\t\t\t});\n\t\t}\n\t\tlibrary.items = library.items.filter(item => files.includes(item.filename));\n\t\tlibrary.items.sort((a, b) => (b.uploadedAt || 0) - (a.uploadedAt || 0));\n\t\treturn library;\n\t}\n\n\t/**\n\t * Custom pictogram library (user-owned images only).\n\t * ARASAAC images must never be uploaded here \u2013 use external IDs only.\n\t *\n\t * @param obj\n\t */\n\tprivate async onMessage(obj: ioBroker.Message): Promise<void> {\n\t\tif (!obj?.command) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tif (obj.command === \"syncPictogramTable\") {\n\t\t\t\tawait this.ensurePictogramStore();\n\t\t\t\tconst rows = await this.buildCustomPictogramRows();\n\t\t\t\tawait this.extendObject(`system.adapter.${this.namespace}`, {\n\t\t\t\t\tnative: { customPictograms: rows },\n\t\t\t\t});\n\t\t\t\tthis.config.customPictograms = rows;\n\t\t\t\tawait this.publishPictogramLibrary();\n\t\t\t\tthis.reply(obj, { ok: true, native: { customPictograms: rows } });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (obj.command === \"syncWeeklyPlansTable\") {\n\t\t\t\tconst nativeMsg = obj.message as {\n\t\t\t\t\tweeklyPlanRows?: Array<{ id?: string; name?: string; active?: string }>;\n\t\t\t\t};\n\t\t\t\tif (Array.isArray(nativeMsg?.weeklyPlanRows)) {\n\t\t\t\t\tthis.config.weeklyPlanRows = nativeMsg.weeklyPlanRows;\n\t\t\t\t\tawait this.applyWeeklyPlanRowsFromConfig();\n\t\t\t\t}\n\t\t\t\tawait this.syncWeeklyPlansTableToNative();\n\t\t\t\tconst library = await this.getWeeklyPlansLibrary();\n\t\t\t\tthis.reply(obj, {\n\t\t\t\t\tok: true,\n\t\t\t\t\tnative: { weeklyPlanRows: this.config.weeklyPlanRows || [] },\n\t\t\t\t\tactiveId: library.activeId,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (obj.command === \"uploadPictogram\") {\n\t\t\t\tconst payload = obj.message as {\n\t\t\t\t\tfilename?: string;\n\t\t\t\t\tbase64?: string;\n\t\t\t\t\tmime?: string;\n\t\t\t\t\tlabel?: string;\n\t\t\t\t\ttags?: string[] | string;\n\t\t\t\t};\n\t\t\t\tconst originalName = String(payload?.filename || \"image.png\");\n\t\t\t\tconst filename = uniquePictogramFilename(originalName);\n\t\t\t\tconst base64 = String(payload?.base64 || \"\");\n\t\t\t\tif (!base64) {\n\t\t\t\t\tthrow new Error(\"filename and base64 required\");\n\t\t\t\t}\n\t\t\t\tif (!/\\.(png|jpe?g|gif|webp|svg)$/i.test(filename)) {\n\t\t\t\t\tthrow new Error(\"unsupported file type\");\n\t\t\t\t}\n\t\t\t\tconst buffer = Buffer.from(base64.replace(/^data:[^;]+;base64,/, \"\"), \"base64\");\n\t\t\t\tif (!buffer.length) {\n\t\t\t\t\tthrow new Error(\"empty file\");\n\t\t\t\t}\n\t\t\t\tif (buffer.length > 5 * 1024 * 1024) {\n\t\t\t\t\tthrow new Error(\"file too large (max 5 MB)\");\n\t\t\t\t}\n\t\t\t\tconst path = pictogramStoragePath(filename);\n\t\t\t\tawait this.writeFileAsync(PICTOGRAM_FILE_ADAPTER, path, buffer);\n\t\t\t\tconst library = await this.getMergedPictogramLibrary();\n\t\t\t\tconst entry: CustomPictogram = {\n\t\t\t\t\tid: filename,\n\t\t\t\t\tfilename,\n\t\t\t\t\tpath,\n\t\t\t\t\tlabel: String(payload?.label || originalName.replace(/\\.[^.]+$/, \"\")),\n\t\t\t\t\ttags: normalizeTags(payload?.tags),\n\t\t\t\t\toriginalName,\n\t\t\t\t\tmime: String(payload?.mime || \"\"),\n\t\t\t\t\tuploadedAt: Date.now(),\n\t\t\t\t};\n\t\t\t\tlibrary.items = [entry, ...library.items.filter(item => item.filename !== filename)];\n\t\t\t\tawait this.savePictogramLibrary(library);\n\t\t\t\tawait this.syncCustomPictogramsConfig();\n\t\t\t\tthis.log.info(`Custom pictogram stored: ${PICTOGRAM_FILE_ADAPTER}/${path} (${buffer.length} bytes)`);\n\t\t\t\tthis.reply(obj, {\n\t\t\t\t\tok: true,\n\t\t\t\t\tpath,\n\t\t\t\t\turl: pictogramPublicUrl(path),\n\t\t\t\t\titem: entry,\n\t\t\t\t\tlibrary,\n\t\t\t\t\tadapter: PICTOGRAM_FILE_ADAPTER,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (obj.command === \"listPictograms\") {\n\t\t\t\tconst library = await this.getPublishedPictogramLibrary();\n\t\t\t\tthis.reply(obj, {\n\t\t\t\t\tok: true,\n\t\t\t\t\tfiles: library.items.map(item => item.filename),\n\t\t\t\t\tlibrary,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (obj.command === \"updatePictogram\") {\n\t\t\t\tconst payload = obj.message as {\n\t\t\t\t\tpath?: string;\n\t\t\t\t\tfilename?: string;\n\t\t\t\t\tlabel?: string;\n\t\t\t\t\ttags?: string[] | string;\n\t\t\t\t};\n\t\t\t\tconst key = String(payload?.path || payload?.filename || \"\");\n\t\t\t\tif (!key) {\n\t\t\t\t\tthrow new Error(\"path required\");\n\t\t\t\t}\n\t\t\t\tconst library = await this.getMergedPictogramLibrary();\n\t\t\t\tconst item = library.items.find(entry => matchesPictogramKey(entry, key));\n\t\t\t\tif (!item) {\n\t\t\t\t\tthrow new Error(\"pictogram not found\");\n\t\t\t\t}\n\t\t\t\tif (payload.label !== undefined) {\n\t\t\t\t\titem.label = String(payload.label);\n\t\t\t\t}\n\t\t\t\tif (payload.tags !== undefined) {\n\t\t\t\t\titem.tags = normalizeTags(payload.tags);\n\t\t\t\t}\n\t\t\t\tawait this.savePictogramLibrary(library);\n\t\t\t\tthis.reply(obj, { ok: true, item, library });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (obj.command === \"deletePictogram\") {\n\t\t\t\tconst payload = obj.message as { path?: string; filename?: string };\n\t\t\t\tconst key = String(payload?.path || payload?.filename || \"\");\n\t\t\t\tif (!key) {\n\t\t\t\t\tthrow new Error(\"path required\");\n\t\t\t\t}\n\t\t\t\tconst library = await this.getMergedPictogramLibrary();\n\t\t\t\tconst item = library.items.find(entry => matchesPictogramKey(entry, key));\n\t\t\t\tif (!item) {\n\t\t\t\t\tthrow new Error(\"pictogram not found\");\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tawait this.unlinkAsync(PICTOGRAM_FILE_ADAPTER, item.path);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthis.log.warn(`Could not delete pictogram file ${item.path}: ${(error as Error).message}`);\n\t\t\t\t}\n\t\t\t\tlibrary.items = library.items.filter(entry => entry.filename !== item.filename);\n\t\t\t\tawait this.savePictogramLibrary(library);\n\t\t\t\tthis.reply(obj, { ok: true, library });\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tthis.log.error(`Pictogram command ${obj.command} failed: ${(error as Error).message}`);\n\t\t\tthis.reply(obj, { ok: false, error: (error as Error).message });\n\t\t}\n\t}\n\n\tprivate async applyDurationParts(\n\t\thours: number | undefined,\n\t\tminutes: number | undefined,\n\t\tmaxHours: number,\n\t): Promise<void> {\n\t\tif (!this.timerManager) {\n\t\t\treturn;\n\t\t}\n\t\tconst snapshot = this.timerManager.getSnapshot();\n\t\tconst current = secondsToParts(snapshot.duration);\n\t\tconst nextHours = hours ?? current.hours;\n\t\tconst nextMinutes = minutes ?? current.minutes;\n\t\tconst totalSeconds = nextHours * 3600 + nextMinutes * 60;\n\t\tawait this.timerManager.setDuration(totalSeconds, maxHours);\n\t}\n\n\tprivate onUnload(callback: () => void): void {\n\t\tif (this.scheduleTick !== undefined && this.scheduleTick !== null) {\n\t\t\tthis.clearInterval(this.scheduleTick);\n\t\t\tthis.scheduleTick = null;\n\t\t}\n\t\tthis.timerManager?.destroy();\n\t\tthis.timerManager = null;\n\t\tcallback();\n\t}\n}\n\nif (require.main !== module) {\n\tmodule.exports = (options: Partial<utils.AdapterOptions> | undefined) => new AutismSupport(options);\n} else {\n\t(() => new AutismSupport())();\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/*\n * ioBroker.autism-support \u2013 Visual Countdown + Daily Schedule\n */\n\nimport * as utils from \"@iobroker/adapter-core\";\nimport { TimerManager } from \"./lib/timer-manager\";\nimport {\n\tdayPeriodsFromConfig,\n\tfindCurrentPeriod,\n\tparseTimeToMinutes,\n\ttype DayPeriodDefinition,\n} from \"./lib/day-periods\";\nimport { findCurrentItemIndex, isPlanFullyExpired, parseSchedulePlan, type SchedulePlan } from \"./lib/schedule-types\";\nimport {\n\tADAPTER_LIBRARY_FILE,\n\tPICTOGRAM_DIR,\n\tPICTOGRAM_FILE_ADAPTER,\n\tPICTOGRAM_PLACEHOLDER_FILE,\n\tLEGACY_VIS_LIBRARY_FILE,\n\temptyLibrary,\n\tisIgnoredPictogramFile,\n\tlibraryFromNativeRows,\n\tmatchesPictogramKey,\n\tmergePictogramSources,\n\tnormalizeTags,\n\tparseLibrary,\n\tpictogramPublicUrl,\n\tpictogramStoragePath,\n\tsyncCustomPictogramRows,\n\tuniquePictogramFilename,\n\ttype CustomPictogram,\n\ttype PictogramLibrary,\n} from \"./lib/pictogram-library\";\nimport {\n\tapplyWeeklyPlanRowsToLibrary,\n\tcreateEmptyWeeklyPlan,\n\tparseWeeklyPlan,\n\tparseWeeklyPlansLibrary,\n\tschedulePlansEqual,\n\tweekdayColorsFromConfig,\n\tweekdayKeyFromDate,\n\tweeklyPlanRowsFromLibrary,\n\ttype WeekdayColors,\n\ttype WeekdayKey,\n\ttype WeeklyPlanData,\n\ttype WeeklyPlansLibrary,\n} from \"./lib/weekly-plan\";\n\nconst TIMER_CHANNEL = \"timer\";\nconst SCHEDULE_CHANNEL = \"schedule\";\n\nfunction instanceConfigId(namespace: string): string {\n\treturn `system.adapter.${namespace}`;\n}\n\nfunction legacyMisplacedInstanceConfigId(namespace: string): string {\n\treturn `${namespace}.system.adapter.${namespace}`;\n}\n\nfunction secondsToParts(totalSeconds: number): { hours: number; minutes: number } {\n\tconst safe = Math.max(0, Math.round(totalSeconds));\n\treturn {\n\t\thours: Math.floor(safe / 3600),\n\t\tminutes: Math.floor((safe % 3600) / 60),\n\t};\n}\n\nclass AutismSupport extends utils.Adapter {\n\tprivate timerManager: TimerManager | null = null;\n\tprivate scheduleTick: ioBroker.Interval | undefined | null = null;\n\tprivate dayPeriods: DayPeriodDefinition[] = [];\n\tprivate weekdayColors: WeekdayColors = weekdayColorsFromConfig({} as ioBroker.AdapterConfig);\n\tprivate lastAppliedWeekday: WeekdayKey | null = null;\n\n\tpublic constructor(options: Partial<utils.AdapterOptions> = {}) {\n\t\tsuper({\n\t\t\t...options,\n\t\t\tname: \"autism-support\",\n\t\t});\n\t\tthis.on(\"ready\", this.onReady.bind(this));\n\t\tthis.on(\"stateChange\", this.onStateChange.bind(this));\n\t\tthis.on(\"message\", this.onMessage.bind(this));\n\t\tthis.on(\"unload\", this.onUnload.bind(this));\n\t}\n\n\tprivate async onReady(): Promise<void> {\n\t\tconst maxHours = this.config.maxDurationHours ?? 24;\n\t\tconst defaultSeconds = this.getDefaultDurationSeconds(maxHours);\n\t\tthis.dayPeriods = dayPeriodsFromConfig(this.config);\n\t\tthis.weekdayColors = weekdayColorsFromConfig(this.config);\n\n\t\tawait this.migrateMisplacedInstanceConfig();\n\t\tawait this.createTimerStates();\n\t\tawait this.ensurePictogramStore();\n\t\tawait this.syncCustomPictogramsConfig();\n\t\tawait this.createScheduleStates();\n\t\t// Only apply Admin name/delete edits when the table already lists plans (avoid wiping on first boot).\n\t\tif (Array.isArray(this.config.weeklyPlanRows) && this.config.weeklyPlanRows.length > 0) {\n\t\t\tawait this.applyWeeklyPlanRowsFromConfig();\n\t\t}\n\t\tawait this.syncWeeklyPlansTableToNative();\n\n\t\tthis.timerManager = new TimerManager(\n\t\t\tasync snapshot => {\n\t\t\t\tawait this.publishTimerSnapshot(snapshot);\n\t\t\t},\n\t\t\t{\n\t\t\t\tsetInterval: (handler, ms) => this.setInterval(handler, ms),\n\t\t\t\tclearInterval: handle => this.clearInterval(handle as ioBroker.Interval),\n\t\t\t},\n\t\t);\n\n\t\tawait this.timerManager.setDuration(defaultSeconds, maxHours);\n\t\tawait this.publishTimerSnapshot(this.timerManager.getSnapshot());\n\t\tawait this.publishScheduleRuntime();\n\n\t\tthis.subscribeStates(`${this.namespace}.${TIMER_CHANNEL}.*`);\n\t\tthis.subscribeStates(`${this.namespace}.${SCHEDULE_CHANNEL}.*`);\n\n\t\tthis.scheduleTick = this.setInterval(() => {\n\t\t\tvoid this.publishScheduleRuntime();\n\t\t}, 30_000);\n\n\t\tthis.log.info(\"Autism Support adapter ready \u2013 Visual Countdown + Weekly Schedule\");\n\t}\n\n\tprivate getDefaultDurationSeconds(maxHours: number): number {\n\t\tconst hours = Math.min(maxHours, Math.max(0, this.config.defaultDurationHours ?? 1));\n\t\tconst minutes = Math.min(59, Math.max(0, this.config.defaultDurationMinutes ?? 0));\n\t\tconst total = hours * 3600 + minutes * 60;\n\t\treturn Math.max(60, Math.min(maxHours * 3600, total));\n\t}\n\n\tprivate async createTimerStates(): Promise<void> {\n\t\tawait this.setObjectNotExistsAsync(TIMER_CHANNEL, {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: \"Visual Countdown\" },\n\t\t\tnative: {},\n\t\t});\n\n\t\tconst states: Record<\n\t\t\tstring,\n\t\t\t{\n\t\t\t\ttype: \"number\" | \"boolean\";\n\t\t\t\trole: string;\n\t\t\t\tname: string;\n\t\t\t\tread: boolean;\n\t\t\t\twrite: boolean;\n\t\t\t\tunit?: string;\n\t\t\t\tmin?: number;\n\t\t\t\tmax?: number;\n\t\t\t}\n\t\t> = {\n\t\t\tduration: {\n\t\t\t\ttype: \"number\",\n\t\t\t\trole: \"level.timer\",\n\t\t\t\tname: \"Timer duration (seconds)\",\n\t\t\t\tread: true,\n\t\t\t\twrite: true,\n\t\t\t\tunit: \"s\",\n\t\t\t\tmin: 60,\n\t\t\t\tmax: 86400,\n\t\t\t},\n\t\t\tremaining: {\n\t\t\t\ttype: \"number\",\n\t\t\t\trole: \"value.timer\",\n\t\t\t\tname: \"Timer remaining (seconds)\",\n\t\t\t\tread: true,\n\t\t\t\twrite: false,\n\t\t\t\tunit: \"s\",\n\t\t\t},\n\t\t\telapsed: {\n\t\t\t\ttype: \"number\",\n\t\t\t\trole: \"value.timer\",\n\t\t\t\tname: \"Timer elapsed (seconds)\",\n\t\t\t\tread: true,\n\t\t\t\twrite: false,\n\t\t\t\tunit: \"s\",\n\t\t\t},\n\t\t\trunning: {\n\t\t\t\ttype: \"boolean\",\n\t\t\t\trole: \"indicator\",\n\t\t\t\tname: \"Timer running\",\n\t\t\t\tread: true,\n\t\t\t\twrite: false,\n\t\t\t},\n\t\t\tpaused: {\n\t\t\t\ttype: \"boolean\",\n\t\t\t\trole: \"indicator\",\n\t\t\t\tname: \"Timer paused\",\n\t\t\t\tread: true,\n\t\t\t\twrite: false,\n\t\t\t},\n\t\t\tfinished: {\n\t\t\t\ttype: \"boolean\",\n\t\t\t\trole: \"indicator\",\n\t\t\t\tname: \"Timer finished\",\n\t\t\t\tread: true,\n\t\t\t\twrite: false,\n\t\t\t},\n\t\t\tstart: {\n\t\t\t\ttype: \"boolean\",\n\t\t\t\trole: \"button.start\",\n\t\t\t\tname: \"Start timer\",\n\t\t\t\tread: false,\n\t\t\t\twrite: true,\n\t\t\t},\n\t\t\tpause: {\n\t\t\t\ttype: \"boolean\",\n\t\t\t\trole: \"button.pause\",\n\t\t\t\tname: \"Pause timer\",\n\t\t\t\tread: false,\n\t\t\t\twrite: true,\n\t\t\t},\n\t\t\tresume: {\n\t\t\t\ttype: \"boolean\",\n\t\t\t\trole: \"button.start\",\n\t\t\t\tname: \"Resume timer\",\n\t\t\t\tread: false,\n\t\t\t\twrite: true,\n\t\t\t},\n\t\t\tstop: {\n\t\t\t\ttype: \"boolean\",\n\t\t\t\trole: \"button.stop\",\n\t\t\t\tname: \"Stop timer\",\n\t\t\t\tread: false,\n\t\t\t\twrite: true,\n\t\t\t},\n\t\t\tsetDurationHours: {\n\t\t\t\ttype: \"number\",\n\t\t\t\trole: \"level\",\n\t\t\t\tname: \"Set timer duration (hours)\",\n\t\t\t\tread: true,\n\t\t\t\twrite: true,\n\t\t\t\tunit: \"h\",\n\t\t\t\tmin: 0,\n\t\t\t\tmax: 24,\n\t\t\t},\n\t\t\tsetDurationMinutes: {\n\t\t\t\ttype: \"number\",\n\t\t\t\trole: \"level\",\n\t\t\t\tname: \"Set timer duration (minutes)\",\n\t\t\t\tread: true,\n\t\t\t\twrite: true,\n\t\t\t\tunit: \"min\",\n\t\t\t\tmin: 0,\n\t\t\t\tmax: 59,\n\t\t\t},\n\t\t};\n\n\t\tfor (const [id, def] of Object.entries(states)) {\n\t\t\tawait this.setObjectNotExistsAsync(`${TIMER_CHANNEL}.${id}`, {\n\t\t\t\ttype: \"state\",\n\t\t\t\tcommon: {\n\t\t\t\t\tname: def.name,\n\t\t\t\t\ttype: def.type,\n\t\t\t\t\trole: def.role,\n\t\t\t\t\tread: def.read,\n\t\t\t\t\twrite: def.write,\n\t\t\t\t\tunit: def.unit,\n\t\t\t\t\tmin: def.min,\n\t\t\t\t\tmax: def.max,\n\t\t\t\t},\n\t\t\t\tnative: {},\n\t\t\t});\n\t\t}\n\n\t\tawait this.migrateTimerStateRoles();\n\t}\n\n\t/**\n\t * Earlier versions used extendObject() for system.adapter.* which ioBroker resolves\n\t * relative to the instance namespace (autism-support.0.system.adapter...).\n\t */\n\tprivate async migrateMisplacedInstanceConfig(): Promise<void> {\n\t\tconst legacyId = legacyMisplacedInstanceConfigId(this.namespace);\n\t\tconst legacy = await this.getObjectAsync(legacyId);\n\t\tif (!legacy?.native) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst native = legacy.native as {\n\t\t\tcustomPictograms?: ioBroker.AdapterConfig[\"customPictograms\"];\n\t\t\tweeklyPlanRows?: ioBroker.AdapterConfig[\"weeklyPlanRows\"];\n\t\t};\n\t\tconst patch: Partial<ioBroker.AdapterConfig> = {};\n\t\tif (Array.isArray(native.customPictograms)) {\n\t\t\tpatch.customPictograms = native.customPictograms;\n\t\t}\n\t\tif (Array.isArray(native.weeklyPlanRows)) {\n\t\t\tpatch.weeklyPlanRows = native.weeklyPlanRows;\n\t\t}\n\t\tif (Object.keys(patch).length) {\n\t\t\tawait this.extendForeignObjectAsync(instanceConfigId(this.namespace), { native: patch });\n\t\t\tif (patch.customPictograms) {\n\t\t\t\tthis.config.customPictograms = patch.customPictograms;\n\t\t\t}\n\t\t\tif (patch.weeklyPlanRows) {\n\t\t\t\tthis.config.weeklyPlanRows = patch.weeklyPlanRows;\n\t\t\t}\n\t\t\tthis.log.info(`Migrated instance native config from misplaced object ${legacyId}`);\n\t\t}\n\n\t\tawait this.delObjectAsync(legacyId);\n\t\tfor (const folderId of [`${this.namespace}.system.adapter`, `${this.namespace}.system`]) {\n\t\t\ttry {\n\t\t\t\tawait this.delObjectAsync(folderId);\n\t\t\t} catch {\n\t\t\t\t// folder may not exist or is not empty\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Update roles/read flags on existing timer states (object-structure compliance). */\n\tprivate async migrateTimerStateRoles(): Promise<void> {\n\t\tconst patches: Record<string, { role?: string; read?: boolean }> = {\n\t\t\tduration: { role: \"level.timer\" },\n\t\t\tremaining: { role: \"value.timer\" },\n\t\t\telapsed: { role: \"value.timer\" },\n\t\t\tstart: { read: false },\n\t\t\tpause: { read: false },\n\t\t\tresume: { read: false },\n\t\t\tstop: { read: false },\n\t\t};\n\t\tfor (const [id, patch] of Object.entries(patches)) {\n\t\t\tconst common: Partial<ioBroker.StateCommon> = {};\n\t\t\tif (patch.role) {\n\t\t\t\tcommon.role = patch.role;\n\t\t\t}\n\t\t\tif (patch.read !== undefined) {\n\t\t\t\tcommon.read = patch.read;\n\t\t\t}\n\t\t\tawait this.extendObjectAsync(`${TIMER_CHANNEL}.${id}`, { common });\n\t\t}\n\t}\n\n\tprivate async createScheduleStates(): Promise<void> {\n\t\tawait this.setObjectNotExistsAsync(SCHEDULE_CHANNEL, {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: \"Daily schedule\" },\n\t\t\tnative: {},\n\t\t});\n\n\t\tawait this.setObjectNotExistsAsync(`${SCHEDULE_CHANNEL}.plan`, {\n\t\t\ttype: \"state\",\n\t\t\tcommon: {\n\t\t\t\tname: \"Schedule plan (JSON)\",\n\t\t\t\ttype: \"string\",\n\t\t\t\trole: \"json\",\n\t\t\t\tread: true,\n\t\t\t\twrite: true,\n\t\t\t\tdef: JSON.stringify({ version: 1, items: [] }),\n\t\t\t},\n\t\t\tnative: {},\n\t\t});\n\n\t\tawait this.setObjectNotExistsAsync(`${SCHEDULE_CHANNEL}.periods`, {\n\t\t\ttype: \"state\",\n\t\t\tcommon: {\n\t\t\t\tname: \"Day periods from admin (JSON)\",\n\t\t\t\ttype: \"string\",\n\t\t\t\trole: \"json\",\n\t\t\t\tread: true,\n\t\t\t\twrite: false,\n\t\t\t},\n\t\t\tnative: {},\n\t\t});\n\n\t\tawait this.setObjectNotExistsAsync(`${SCHEDULE_CHANNEL}.periodOverrides`, {\n\t\t\ttype: \"state\",\n\t\t\tcommon: {\n\t\t\t\tname: \"Day period on/off overrides from schedule config (JSON)\",\n\t\t\t\ttype: \"string\",\n\t\t\t\trole: \"json\",\n\t\t\t\tread: true,\n\t\t\t\twrite: true,\n\t\t\t\tdef: \"{}\",\n\t\t\t},\n\t\t\tnative: {},\n\t\t});\n\n\t\tawait this.setObjectNotExistsAsync(`${SCHEDULE_CHANNEL}.nowMinutes`, {\n\t\t\ttype: \"state\",\n\t\t\tcommon: {\n\t\t\t\tname: \"Minutes since midnight (local)\",\n\t\t\t\ttype: \"number\",\n\t\t\t\trole: \"value\",\n\t\t\t\tread: true,\n\t\t\t\twrite: false,\n\t\t\t\tunit: \"min\",\n\t\t\t\tmin: 0,\n\t\t\t\tmax: 1439,\n\t\t\t},\n\t\t\tnative: {},\n\t\t});\n\n\t\tawait this.setObjectNotExistsAsync(`${SCHEDULE_CHANNEL}.currentPeriod`, {\n\t\t\ttype: \"state\",\n\t\t\tcommon: {\n\t\t\t\tname: \"Current day period id\",\n\t\t\t\ttype: \"string\",\n\t\t\t\trole: \"text\",\n\t\t\t\tread: true,\n\t\t\t\twrite: false,\n\t\t\t},\n\t\t\tnative: {},\n\t\t});\n\n\t\tawait this.setObjectNotExistsAsync(`${SCHEDULE_CHANNEL}.currentItemIndex`, {\n\t\t\ttype: \"state\",\n\t\t\tcommon: {\n\t\t\t\tname: \"Index of active schedule item (-1 = none)\",\n\t\t\t\ttype: \"number\",\n\t\t\t\trole: \"value\",\n\t\t\t\tread: true,\n\t\t\t\twrite: false,\n\t\t\t\tmin: -1,\n\t\t\t},\n\t\t\tnative: {},\n\t\t});\n\n\t\tawait this.setObjectNotExistsAsync(`${SCHEDULE_CHANNEL}.clearAfterLast`, {\n\t\t\ttype: \"state\",\n\t\t\tcommon: {\n\t\t\t\tname: \"Clear plan automatically after last pictogram ends\",\n\t\t\t\ttype: \"boolean\",\n\t\t\t\trole: \"switch\",\n\t\t\t\tread: true,\n\t\t\t\twrite: true,\n\t\t\t\tdef: false,\n\t\t\t},\n\t\t\tnative: {},\n\t\t});\n\n\t\tawait this.setObjectNotExistsAsync(`${SCHEDULE_CHANNEL}.pictogramLibrary`, {\n\t\t\ttype: \"state\",\n\t\t\tcommon: {\n\t\t\t\tname: \"Custom pictogram library (JSON)\",\n\t\t\t\ttype: \"string\",\n\t\t\t\trole: \"json\",\n\t\t\t\tread: true,\n\t\t\t\twrite: false,\n\t\t\t},\n\t\t\tnative: {},\n\t\t});\n\n\t\tawait this.setObjectNotExistsAsync(`${SCHEDULE_CHANNEL}.weeklyPlan`, {\n\t\t\ttype: \"state\",\n\t\t\tcommon: {\n\t\t\t\tname: \"Active weekly plan (JSON, Mon\u2013Sun)\",\n\t\t\t\ttype: \"string\",\n\t\t\t\trole: \"json\",\n\t\t\t\tread: true,\n\t\t\t\twrite: true,\n\t\t\t\tdef: JSON.stringify(createEmptyWeeklyPlan()),\n\t\t\t},\n\t\t\tnative: {},\n\t\t});\n\n\t\tawait this.setObjectNotExistsAsync(`${SCHEDULE_CHANNEL}.weeklyPlansLibrary`, {\n\t\t\ttype: \"state\",\n\t\t\tcommon: {\n\t\t\t\tname: \"Saved weekly plans library (JSON)\",\n\t\t\t\ttype: \"string\",\n\t\t\t\trole: \"json\",\n\t\t\t\tread: true,\n\t\t\t\twrite: true,\n\t\t\t\tdef: JSON.stringify({ version: 1, activeId: null, plans: [] }),\n\t\t\t},\n\t\t\tnative: {},\n\t\t});\n\n\t\tawait this.setObjectNotExistsAsync(`${SCHEDULE_CHANNEL}.loadDailyFromWeekly`, {\n\t\t\ttype: \"state\",\n\t\t\tcommon: {\n\t\t\t\tname: \"Load daily plan from active weekly plan each day\",\n\t\t\t\ttype: \"boolean\",\n\t\t\t\trole: \"switch\",\n\t\t\t\tread: true,\n\t\t\t\twrite: true,\n\t\t\t\tdef: false,\n\t\t\t},\n\t\t\tnative: {},\n\t\t});\n\n\t\tawait this.setObjectNotExistsAsync(`${SCHEDULE_CHANNEL}.weekdayColors`, {\n\t\t\ttype: \"state\",\n\t\t\tcommon: {\n\t\t\t\tname: \"Weekday background colors from admin (JSON)\",\n\t\t\t\ttype: \"string\",\n\t\t\t\trole: \"json\",\n\t\t\t\tread: true,\n\t\t\t\twrite: false,\n\t\t\t},\n\t\t\tnative: {},\n\t\t});\n\n\t\tconst planState = await this.getStateAsync(`${SCHEDULE_CHANNEL}.plan`);\n\t\tif (planState?.val == null || planState.val === \"\") {\n\t\t\tawait this.setState(`${SCHEDULE_CHANNEL}.plan`, JSON.stringify({ version: 1, items: [] }), true);\n\t\t}\n\t\tconst overridesState = await this.getStateAsync(`${SCHEDULE_CHANNEL}.periodOverrides`);\n\t\tif (overridesState?.val == null || overridesState.val === \"\") {\n\t\t\tawait this.setState(`${SCHEDULE_CHANNEL}.periodOverrides`, \"{}\", true);\n\t\t}\n\t\tconst clearAfterState = await this.getStateAsync(`${SCHEDULE_CHANNEL}.clearAfterLast`);\n\t\tif (clearAfterState?.val == null) {\n\t\t\tawait this.setState(`${SCHEDULE_CHANNEL}.clearAfterLast`, false, true);\n\t\t}\n\t\tconst loadDailyState = await this.getStateAsync(`${SCHEDULE_CHANNEL}.loadDailyFromWeekly`);\n\t\tif (loadDailyState?.val == null) {\n\t\t\tawait this.setState(`${SCHEDULE_CHANNEL}.loadDailyFromWeekly`, false, true);\n\t\t}\n\n\t\tconst weeklyState = await this.getStateAsync(`${SCHEDULE_CHANNEL}.weeklyPlan`);\n\t\tif (weeklyState?.val == null || weeklyState.val === \"\") {\n\t\t\tconst seed = parseSchedulePlan(planState?.val);\n\t\t\tawait this.setState(\n\t\t\t\t`${SCHEDULE_CHANNEL}.weeklyPlan`,\n\t\t\t\tJSON.stringify(createEmptyWeeklyPlan(seed.items.length ? seed : undefined)),\n\t\t\t\ttrue,\n\t\t\t);\n\t\t}\n\t\tconst libraryState = await this.getStateAsync(`${SCHEDULE_CHANNEL}.weeklyPlansLibrary`);\n\t\tif (libraryState?.val == null || libraryState.val === \"\") {\n\t\t\tawait this.setState(\n\t\t\t\t`${SCHEDULE_CHANNEL}.weeklyPlansLibrary`,\n\t\t\t\tJSON.stringify({ version: 1, activeId: null, plans: [] }),\n\t\t\t\ttrue,\n\t\t\t);\n\t\t}\n\n\t\t// Publish admin period definitions once at start (times/colors); overrides stay separate.\n\t\tawait this.setState(`${SCHEDULE_CHANNEL}.periods`, JSON.stringify(this.dayPeriods), true);\n\t\tawait this.setState(`${SCHEDULE_CHANNEL}.weekdayColors`, JSON.stringify(this.weekdayColors), true);\n\t\tawait this.publishPictogramLibrary();\n\t}\n\n\tprivate async buildCustomPictogramRows(): Promise<Array<{ file: string; label: string; tags: string }>> {\n\t\tconst files = await this.listPictogramFiles();\n\t\treturn syncCustomPictogramRows(files || [], this.config.customPictograms);\n\t}\n\n\tprivate async syncCustomPictogramsConfig(): Promise<void> {\n\t\tconst rows = await this.buildCustomPictogramRows();\n\t\tawait this.extendForeignObjectAsync(instanceConfigId(this.namespace), {\n\t\t\tnative: { customPictograms: rows },\n\t\t});\n\t\tthis.config.customPictograms = rows;\n\t\tawait this.publishPictogramLibrary();\n\t}\n\n\tprivate async ensurePictogramStore(): Promise<void> {\n\t\ttry {\n\t\t\tawait this.readFileAsync(this.namespace, ADAPTER_LIBRARY_FILE);\n\t\t} catch {\n\t\t\ttry {\n\t\t\t\tawait this.writeFileAsync(\n\t\t\t\t\tthis.namespace,\n\t\t\t\t\tADAPTER_LIBRARY_FILE,\n\t\t\t\t\tJSON.stringify(emptyLibrary(), null, 2),\n\t\t\t\t);\n\t\t\t\tthis.log.info(`Created adapter pictogram library ${this.namespace}/${ADAPTER_LIBRARY_FILE}`);\n\t\t\t} catch (error) {\n\t\t\t\tthis.log.error(`Could not create adapter pictogram library: ${(error as Error).message}`);\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\tconst legacy = await this.readFileAsync(PICTOGRAM_FILE_ADAPTER, LEGACY_VIS_LIBRARY_FILE);\n\t\t\tconst raw = typeof legacy.file === \"string\" ? legacy.file : Buffer.from(legacy.file).toString(\"utf8\");\n\t\t\tconst migrated = parseLibrary(raw);\n\t\t\tif (migrated.items.length) {\n\t\t\t\tawait this.writeFileAsync(this.namespace, ADAPTER_LIBRARY_FILE, JSON.stringify(migrated, null, 2));\n\t\t\t\tthis.log.info(`Migrated pictogram library from vis-2 to ${this.namespace}`);\n\t\t\t}\n\t\t} catch {\n\t\t\t// no legacy library in vis-2\n\t\t}\n\n\t\ttry {\n\t\t\tawait this.unlinkAsync(PICTOGRAM_FILE_ADAPTER, LEGACY_VIS_LIBRARY_FILE);\n\t\t} catch {\n\t\t\t// ignore\n\t\t}\n\n\t\ttry {\n\t\t\tconst hint =\n\t\t\t\t\"Piktogramm-Bilder (PNG, JPEG, GIF, WebP, SVG) hier hochladen.\\n\" +\n\t\t\t\t\"Keine neuen Ordner anlegen (Dateimanager zeigt dann oft \u201Edoppelter Name\u201C).\\n\" +\n\t\t\t\t\"Stattdessen oben auf Hochladen klicken und Bilder in DIESEN Ordner legen.\\n\";\n\t\t\tawait this.writeFileAsync(PICTOGRAM_FILE_ADAPTER, `${PICTOGRAM_DIR}/${PICTOGRAM_PLACEHOLDER_FILE}`, hint);\n\t\t\tthis.log.info(`Ensured vis-2 pictogram folder ${PICTOGRAM_FILE_ADAPTER}/${PICTOGRAM_DIR}`);\n\t\t} catch (error) {\n\t\t\tthis.log.error(\n\t\t\t\t`Could not write ${PICTOGRAM_FILE_ADAPTER}/${PICTOGRAM_DIR}/${PICTOGRAM_PLACEHOLDER_FILE}: ${(error as Error).message}`,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate async getPublishedPictogramLibrary(): Promise<PictogramLibrary> {\n\t\treturn mergePictogramSources(\n\t\t\tawait this.getMergedPictogramLibrary(),\n\t\t\tlibraryFromNativeRows(this.config.customPictograms),\n\t\t);\n\t}\n\n\tprivate async publishPictogramLibrary(): Promise<void> {\n\t\tconst library = await this.getPublishedPictogramLibrary();\n\t\tawait this.setState(`${SCHEDULE_CHANNEL}.pictogramLibrary`, JSON.stringify(library), true);\n\t}\n\n\tprivate async publishTimerSnapshot(snapshot: {\n\t\tduration: number;\n\t\tremaining: number;\n\t\telapsed: number;\n\t\trunning: boolean;\n\t\tpaused: boolean;\n\t\tfinished: boolean;\n\t}): Promise<void> {\n\t\tawait this.setState(`${TIMER_CHANNEL}.duration`, snapshot.duration, true);\n\t\tawait this.setState(`${TIMER_CHANNEL}.remaining`, snapshot.remaining, true);\n\t\tawait this.setState(`${TIMER_CHANNEL}.elapsed`, snapshot.elapsed, true);\n\t\tawait this.setState(`${TIMER_CHANNEL}.running`, snapshot.running, true);\n\t\tawait this.setState(`${TIMER_CHANNEL}.paused`, snapshot.paused, true);\n\t\tawait this.setState(`${TIMER_CHANNEL}.finished`, snapshot.finished, true);\n\t}\n\n\tprivate async getPlan(): Promise<SchedulePlan> {\n\t\tconst state = await this.getStateAsync(`${SCHEDULE_CHANNEL}.plan`);\n\t\treturn parseSchedulePlan(state?.val);\n\t}\n\n\tprivate async getPeriodOverrides(): Promise<Record<string, boolean>> {\n\t\tconst state = await this.getStateAsync(`${SCHEDULE_CHANNEL}.periodOverrides`);\n\t\ttry {\n\t\t\tconst raw = typeof state?.val === \"string\" ? JSON.parse(state.val) : state?.val;\n\t\t\treturn raw && typeof raw === \"object\" ? (raw as Record<string, boolean>) : {};\n\t\t} catch {\n\t\t\treturn {};\n\t\t}\n\t}\n\n\tprivate async getEffectivePeriods(): Promise<DayPeriodDefinition[]> {\n\t\tconst overrides = await this.getPeriodOverrides();\n\t\treturn this.dayPeriods.map(period => ({\n\t\t\t...period,\n\t\t\tenabled: overrides[period.id] === undefined ? period.enabled : Boolean(overrides[period.id]),\n\t\t}));\n\t}\n\n\tprivate async getWeeklyPlan(): Promise<WeeklyPlanData> {\n\t\tconst state = await this.getStateAsync(`${SCHEDULE_CHANNEL}.weeklyPlan`);\n\t\treturn parseWeeklyPlan(state?.val);\n\t}\n\n\tprivate async getWeeklyPlansLibrary(): Promise<WeeklyPlansLibrary> {\n\t\tconst state = await this.getStateAsync(`${SCHEDULE_CHANNEL}.weeklyPlansLibrary`);\n\t\treturn parseWeeklyPlansLibrary(state?.val);\n\t}\n\n\tprivate async syncWeeklyPlansTableToNative(): Promise<void> {\n\t\tconst library = await this.getWeeklyPlansLibrary();\n\t\tconst rows = weeklyPlanRowsFromLibrary(library);\n\t\tawait this.extendForeignObjectAsync(instanceConfigId(this.namespace), {\n\t\t\tnative: { weeklyPlanRows: rows },\n\t\t});\n\t\tthis.config.weeklyPlanRows = rows;\n\t}\n\n\tprivate async applyWeeklyPlanRowsFromConfig(): Promise<void> {\n\t\tconst library = await this.getWeeklyPlansLibrary();\n\t\tconst next = applyWeeklyPlanRowsToLibrary(library, this.config.weeklyPlanRows);\n\t\tif (JSON.stringify(next) !== JSON.stringify(library)) {\n\t\t\tawait this.setState(`${SCHEDULE_CHANNEL}.weeklyPlansLibrary`, JSON.stringify(next), true);\n\t\t}\n\t}\n\n\tprivate async maybeApplyWeeklyToDaily(): Promise<void> {\n\t\tconst loadState = await this.getStateAsync(`${SCHEDULE_CHANNEL}.loadDailyFromWeekly`);\n\t\tif (!loadState?.val) {\n\t\t\treturn;\n\t\t}\n\t\tconst weekday = weekdayKeyFromDate(new Date());\n\t\tconst weekly = await this.getWeeklyPlan();\n\t\tconst dayPlan = weekly.days[weekday];\n\t\tconst current = await this.getPlan();\n\t\tif (this.lastAppliedWeekday === weekday && schedulePlansEqual(current, dayPlan)) {\n\t\t\treturn;\n\t\t}\n\t\tawait this.setState(`${SCHEDULE_CHANNEL}.plan`, JSON.stringify(dayPlan), true);\n\t\tthis.lastAppliedWeekday = weekday;\n\t\tthis.log.debug(`Daily plan loaded from weekly plan (${weekday})`);\n\t}\n\n\tprivate async publishScheduleRuntime(): Promise<void> {\n\t\tawait this.maybeApplyWeeklyToDaily();\n\n\t\tconst now = new Date();\n\t\tconst minutes = now.getHours() * 60 + now.getMinutes();\n\t\tconst periods = await this.getEffectivePeriods();\n\t\tconst period = findCurrentPeriod(minutes, periods);\n\t\tlet plan = await this.getPlan();\n\n\t\tconst clearAfterState = await this.getStateAsync(`${SCHEDULE_CHANNEL}.clearAfterLast`);\n\t\tconst clearAfterLast = Boolean(clearAfterState?.val);\n\t\tif (clearAfterLast && isPlanFullyExpired(plan, minutes, parseTimeToMinutes)) {\n\t\t\tplan = { version: 1, items: [] };\n\t\t\tawait this.setState(`${SCHEDULE_CHANNEL}.plan`, JSON.stringify(plan), true);\n\t\t\tthis.log.info(\"Schedule plan cleared automatically after last pictogram ended\");\n\t\t}\n\n\t\tconst itemIndex = findCurrentItemIndex(plan, minutes, parseTimeToMinutes);\n\n\t\t// Keep admin period metadata available; do not wipe Config overrides.\n\t\tawait this.setState(`${SCHEDULE_CHANNEL}.periods`, JSON.stringify(this.dayPeriods), true);\n\t\tawait this.setState(`${SCHEDULE_CHANNEL}.weekdayColors`, JSON.stringify(this.weekdayColors), true);\n\t\tawait this.setState(`${SCHEDULE_CHANNEL}.nowMinutes`, minutes, true);\n\t\tawait this.setState(`${SCHEDULE_CHANNEL}.currentPeriod`, period?.id ?? \"\", true);\n\t\tawait this.setState(`${SCHEDULE_CHANNEL}.currentItemIndex`, itemIndex, true);\n\t}\n\n\tprivate async onStateChange(id: string, state: ioBroker.State | null | undefined): Promise<void> {\n\t\tif (!state || state.ack) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (id.startsWith(`${this.namespace}.${SCHEDULE_CHANNEL}.`)) {\n\t\t\tconst localId = id.replace(`${this.namespace}.${SCHEDULE_CHANNEL}.`, \"\");\n\t\t\tif (localId === \"plan\") {\n\t\t\t\tconst plan = parseSchedulePlan(state.val);\n\t\t\t\tawait this.setState(`${SCHEDULE_CHANNEL}.plan`, JSON.stringify(plan), true);\n\t\t\t\tawait this.publishScheduleRuntime();\n\t\t\t} else if (localId === \"periodOverrides\") {\n\t\t\t\ttry {\n\t\t\t\t\tconst raw = typeof state.val === \"string\" ? JSON.parse(String(state.val)) : state.val;\n\t\t\t\t\tconst cleaned = raw && typeof raw === \"object\" ? (raw as Record<string, boolean>) : {};\n\t\t\t\t\tawait this.setState(`${SCHEDULE_CHANNEL}.periodOverrides`, JSON.stringify(cleaned), true);\n\t\t\t\t\tawait this.publishScheduleRuntime();\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthis.log.error(`Invalid periodOverrides: ${(error as Error).message}`);\n\t\t\t\t}\n\t\t\t} else if (localId === \"clearAfterLast\") {\n\t\t\t\tawait this.setState(`${SCHEDULE_CHANNEL}.clearAfterLast`, Boolean(state.val), true);\n\t\t\t\tawait this.publishScheduleRuntime();\n\t\t\t} else if (localId === \"weeklyPlan\") {\n\t\t\t\tconst weekly = parseWeeklyPlan(state.val);\n\t\t\t\tawait this.setState(`${SCHEDULE_CHANNEL}.weeklyPlan`, JSON.stringify(weekly), true);\n\t\t\t\tthis.lastAppliedWeekday = null;\n\t\t\t\tawait this.publishScheduleRuntime();\n\t\t\t} else if (localId === \"weeklyPlansLibrary\") {\n\t\t\t\tconst library = parseWeeklyPlansLibrary(state.val);\n\t\t\t\tawait this.setState(`${SCHEDULE_CHANNEL}.weeklyPlansLibrary`, JSON.stringify(library), true);\n\t\t\t\tawait this.syncWeeklyPlansTableToNative();\n\t\t\t} else if (localId === \"loadDailyFromWeekly\") {\n\t\t\t\tawait this.setState(`${SCHEDULE_CHANNEL}.loadDailyFromWeekly`, Boolean(state.val), true);\n\t\t\t\tthis.lastAppliedWeekday = null;\n\t\t\t\tawait this.publishScheduleRuntime();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this.timerManager || !id.startsWith(`${this.namespace}.${TIMER_CHANNEL}.`)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst localId = id.replace(`${this.namespace}.${TIMER_CHANNEL}.`, \"\");\n\t\tconst maxHours = this.config.maxDurationHours ?? 24;\n\n\t\ttry {\n\t\t\tswitch (localId) {\n\t\t\t\tcase \"start\":\n\t\t\t\t\tif (state.val === true) {\n\t\t\t\t\t\tawait this.timerManager.start();\n\t\t\t\t\t}\n\t\t\t\t\tawait this.setState(`${TIMER_CHANNEL}.start`, false, true);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"pause\":\n\t\t\t\t\tif (state.val === true) {\n\t\t\t\t\t\tawait this.timerManager.pause();\n\t\t\t\t\t}\n\t\t\t\t\tawait this.setState(`${TIMER_CHANNEL}.pause`, false, true);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"resume\":\n\t\t\t\t\tif (state.val === true) {\n\t\t\t\t\t\tawait this.timerManager.resume();\n\t\t\t\t\t}\n\t\t\t\t\tawait this.setState(`${TIMER_CHANNEL}.resume`, false, true);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"stop\":\n\t\t\t\t\tif (state.val === true) {\n\t\t\t\t\t\tawait this.timerManager.stop();\n\t\t\t\t\t}\n\t\t\t\t\tawait this.setState(`${TIMER_CHANNEL}.stop`, false, true);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"duration\":\n\t\t\t\t\tif (typeof state.val === \"number\") {\n\t\t\t\t\t\tawait this.timerManager.setDuration(state.val, maxHours);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"setDurationHours\":\n\t\t\t\t\tif (typeof state.val === \"number\") {\n\t\t\t\t\t\tawait this.applyDurationParts(Math.round(state.val), undefined, maxHours);\n\t\t\t\t\t}\n\t\t\t\t\tawait this.setState(`${TIMER_CHANNEL}.setDurationHours`, 0, true);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"setDurationMinutes\":\n\t\t\t\t\tif (typeof state.val === \"number\") {\n\t\t\t\t\t\tawait this.applyDurationParts(undefined, Math.round(state.val), maxHours);\n\t\t\t\t\t}\n\t\t\t\t\tawait this.setState(`${TIMER_CHANNEL}.setDurationMinutes`, 0, true);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tthis.log.error(`Timer command failed (${localId}): ${(error as Error).message}`);\n\t\t}\n\t}\n\n\tprivate reply(obj: ioBroker.Message, payload: unknown): void {\n\t\tif (obj.callback) {\n\t\t\tthis.sendTo(obj.from, obj.command, payload, obj.callback);\n\t\t}\n\t}\n\n\tprivate async loadPictogramLibrary(): Promise<PictogramLibrary> {\n\t\ttry {\n\t\t\tconst file = await this.readFileAsync(this.namespace, ADAPTER_LIBRARY_FILE);\n\t\t\tconst raw = typeof file.file === \"string\" ? file.file : Buffer.from(file.file).toString(\"utf8\");\n\t\t\treturn parseLibrary(raw);\n\t\t} catch {\n\t\t\treturn emptyLibrary();\n\t\t}\n\t}\n\n\tprivate async savePictogramLibrary(library: PictogramLibrary): Promise<void> {\n\t\tawait this.writeFileAsync(this.namespace, ADAPTER_LIBRARY_FILE, JSON.stringify(library, null, 2));\n\t\tawait this.setState(`${SCHEDULE_CHANNEL}.pictogramLibrary`, JSON.stringify(library), true);\n\t}\n\n\tprivate async listPictogramFiles(): Promise<string[] | null> {\n\t\ttry {\n\t\t\tconst result = await this.readDirAsync(PICTOGRAM_FILE_ADAPTER, PICTOGRAM_DIR);\n\t\t\treturn (result || [])\n\t\t\t\t.filter(entry => !entry.isDir && !isIgnoredPictogramFile(entry.file))\n\t\t\t\t.map(entry => entry.file);\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate async getMergedPictogramLibrary(): Promise<PictogramLibrary> {\n\t\tconst library = await this.loadPictogramLibrary();\n\t\tconst files = await this.listPictogramFiles();\n\t\tif (!files) {\n\t\t\treturn library;\n\t\t}\n\t\tconst known = new Set(library.items.map(item => item.filename));\n\t\tfor (const filename of files) {\n\t\t\tif (known.has(filename)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlibrary.items.push({\n\t\t\t\tid: filename,\n\t\t\t\tfilename,\n\t\t\t\tpath: pictogramStoragePath(filename),\n\t\t\t\tlabel: filename.replace(/\\.[^.]+$/, \"\").replace(/-\\d+$/, \"\"),\n\t\t\t\ttags: [],\n\t\t\t\toriginalName: filename,\n\t\t\t\tmime: \"\",\n\t\t\t\tuploadedAt: 0,\n\t\t\t});\n\t\t}\n\t\tlibrary.items = library.items.filter(item => files.includes(item.filename));\n\t\tlibrary.items.sort((a, b) => (b.uploadedAt || 0) - (a.uploadedAt || 0));\n\t\treturn library;\n\t}\n\n\t/**\n\t * Custom pictogram library (user-owned images only).\n\t * ARASAAC images must never be uploaded here \u2013 use external IDs only.\n\t *\n\t * @param obj\n\t */\n\tprivate async onMessage(obj: ioBroker.Message): Promise<void> {\n\t\tif (!obj?.command) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tif (obj.command === \"syncPictogramTable\") {\n\t\t\t\tawait this.ensurePictogramStore();\n\t\t\t\tconst rows = await this.buildCustomPictogramRows();\n\t\t\t\tawait this.extendForeignObjectAsync(instanceConfigId(this.namespace), {\n\t\t\t\t\tnative: { customPictograms: rows },\n\t\t\t\t});\n\t\t\t\tthis.config.customPictograms = rows;\n\t\t\t\tawait this.publishPictogramLibrary();\n\t\t\t\tthis.reply(obj, { ok: true, native: { customPictograms: rows } });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (obj.command === \"syncWeeklyPlansTable\") {\n\t\t\t\tconst nativeMsg = obj.message as {\n\t\t\t\t\tweeklyPlanRows?: Array<{ id?: string; name?: string; active?: string }>;\n\t\t\t\t};\n\t\t\t\tif (Array.isArray(nativeMsg?.weeklyPlanRows)) {\n\t\t\t\t\tthis.config.weeklyPlanRows = nativeMsg.weeklyPlanRows;\n\t\t\t\t\tawait this.applyWeeklyPlanRowsFromConfig();\n\t\t\t\t}\n\t\t\t\tawait this.syncWeeklyPlansTableToNative();\n\t\t\t\tconst library = await this.getWeeklyPlansLibrary();\n\t\t\t\tthis.reply(obj, {\n\t\t\t\t\tok: true,\n\t\t\t\t\tnative: { weeklyPlanRows: this.config.weeklyPlanRows || [] },\n\t\t\t\t\tactiveId: library.activeId,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (obj.command === \"uploadPictogram\") {\n\t\t\t\tconst payload = obj.message as {\n\t\t\t\t\tfilename?: string;\n\t\t\t\t\tbase64?: string;\n\t\t\t\t\tmime?: string;\n\t\t\t\t\tlabel?: string;\n\t\t\t\t\ttags?: string[] | string;\n\t\t\t\t};\n\t\t\t\tconst originalName = String(payload?.filename || \"image.png\");\n\t\t\t\tconst filename = uniquePictogramFilename(originalName);\n\t\t\t\tconst base64 = String(payload?.base64 || \"\");\n\t\t\t\tif (!base64) {\n\t\t\t\t\tthrow new Error(\"filename and base64 required\");\n\t\t\t\t}\n\t\t\t\tif (!/\\.(png|jpe?g|gif|webp|svg)$/i.test(filename)) {\n\t\t\t\t\tthrow new Error(\"unsupported file type\");\n\t\t\t\t}\n\t\t\t\tconst buffer = Buffer.from(base64.replace(/^data:[^;]+;base64,/, \"\"), \"base64\");\n\t\t\t\tif (!buffer.length) {\n\t\t\t\t\tthrow new Error(\"empty file\");\n\t\t\t\t}\n\t\t\t\tif (buffer.length > 5 * 1024 * 1024) {\n\t\t\t\t\tthrow new Error(\"file too large (max 5 MB)\");\n\t\t\t\t}\n\t\t\t\tconst path = pictogramStoragePath(filename);\n\t\t\t\tawait this.writeFileAsync(PICTOGRAM_FILE_ADAPTER, path, buffer);\n\t\t\t\tconst library = await this.getMergedPictogramLibrary();\n\t\t\t\tconst entry: CustomPictogram = {\n\t\t\t\t\tid: filename,\n\t\t\t\t\tfilename,\n\t\t\t\t\tpath,\n\t\t\t\t\tlabel: String(payload?.label || originalName.replace(/\\.[^.]+$/, \"\")),\n\t\t\t\t\ttags: normalizeTags(payload?.tags),\n\t\t\t\t\toriginalName,\n\t\t\t\t\tmime: String(payload?.mime || \"\"),\n\t\t\t\t\tuploadedAt: Date.now(),\n\t\t\t\t};\n\t\t\t\tlibrary.items = [entry, ...library.items.filter(item => item.filename !== filename)];\n\t\t\t\tawait this.savePictogramLibrary(library);\n\t\t\t\tawait this.syncCustomPictogramsConfig();\n\t\t\t\tthis.log.info(`Custom pictogram stored: ${PICTOGRAM_FILE_ADAPTER}/${path} (${buffer.length} bytes)`);\n\t\t\t\tthis.reply(obj, {\n\t\t\t\t\tok: true,\n\t\t\t\t\tpath,\n\t\t\t\t\turl: pictogramPublicUrl(path),\n\t\t\t\t\titem: entry,\n\t\t\t\t\tlibrary,\n\t\t\t\t\tadapter: PICTOGRAM_FILE_ADAPTER,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (obj.command === \"listPictograms\") {\n\t\t\t\tconst library = await this.getPublishedPictogramLibrary();\n\t\t\t\tthis.reply(obj, {\n\t\t\t\t\tok: true,\n\t\t\t\t\tfiles: library.items.map(item => item.filename),\n\t\t\t\t\tlibrary,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (obj.command === \"updatePictogram\") {\n\t\t\t\tconst payload = obj.message as {\n\t\t\t\t\tpath?: string;\n\t\t\t\t\tfilename?: string;\n\t\t\t\t\tlabel?: string;\n\t\t\t\t\ttags?: string[] | string;\n\t\t\t\t};\n\t\t\t\tconst key = String(payload?.path || payload?.filename || \"\");\n\t\t\t\tif (!key) {\n\t\t\t\t\tthrow new Error(\"path required\");\n\t\t\t\t}\n\t\t\t\tconst library = await this.getMergedPictogramLibrary();\n\t\t\t\tconst item = library.items.find(entry => matchesPictogramKey(entry, key));\n\t\t\t\tif (!item) {\n\t\t\t\t\tthrow new Error(\"pictogram not found\");\n\t\t\t\t}\n\t\t\t\tif (payload.label !== undefined) {\n\t\t\t\t\titem.label = String(payload.label);\n\t\t\t\t}\n\t\t\t\tif (payload.tags !== undefined) {\n\t\t\t\t\titem.tags = normalizeTags(payload.tags);\n\t\t\t\t}\n\t\t\t\tawait this.savePictogramLibrary(library);\n\t\t\t\tthis.reply(obj, { ok: true, item, library });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (obj.command === \"deletePictogram\") {\n\t\t\t\tconst payload = obj.message as { path?: string; filename?: string };\n\t\t\t\tconst key = String(payload?.path || payload?.filename || \"\");\n\t\t\t\tif (!key) {\n\t\t\t\t\tthrow new Error(\"path required\");\n\t\t\t\t}\n\t\t\t\tconst library = await this.getMergedPictogramLibrary();\n\t\t\t\tconst item = library.items.find(entry => matchesPictogramKey(entry, key));\n\t\t\t\tif (!item) {\n\t\t\t\t\tthrow new Error(\"pictogram not found\");\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tawait this.unlinkAsync(PICTOGRAM_FILE_ADAPTER, item.path);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthis.log.warn(`Could not delete pictogram file ${item.path}: ${(error as Error).message}`);\n\t\t\t\t}\n\t\t\t\tlibrary.items = library.items.filter(entry => entry.filename !== item.filename);\n\t\t\t\tawait this.savePictogramLibrary(library);\n\t\t\t\tthis.reply(obj, { ok: true, library });\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tthis.log.error(`Pictogram command ${obj.command} failed: ${(error as Error).message}`);\n\t\t\tthis.reply(obj, { ok: false, error: (error as Error).message });\n\t\t}\n\t}\n\n\tprivate async applyDurationParts(\n\t\thours: number | undefined,\n\t\tminutes: number | undefined,\n\t\tmaxHours: number,\n\t): Promise<void> {\n\t\tif (!this.timerManager) {\n\t\t\treturn;\n\t\t}\n\t\tconst snapshot = this.timerManager.getSnapshot();\n\t\tconst current = secondsToParts(snapshot.duration);\n\t\tconst nextHours = hours ?? current.hours;\n\t\tconst nextMinutes = minutes ?? current.minutes;\n\t\tconst totalSeconds = nextHours * 3600 + nextMinutes * 60;\n\t\tawait this.timerManager.setDuration(totalSeconds, maxHours);\n\t}\n\n\tprivate onUnload(callback: () => void): void {\n\t\tif (this.scheduleTick !== undefined && this.scheduleTick !== null) {\n\t\t\tthis.clearInterval(this.scheduleTick);\n\t\t\tthis.scheduleTick = null;\n\t\t}\n\t\tthis.timerManager?.destroy();\n\t\tthis.timerManager = null;\n\t\tcallback();\n\t}\n}\n\nif (require.main !== module) {\n\tmodule.exports = (options: Partial<utils.AdapterOptions> | undefined) => new AutismSupport(options);\n} else {\n\t(() => new AutismSupport())();\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["localId"]
|
|
7
7
|
}
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,47 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "autism-support",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.5",
|
|
5
5
|
"news": {
|
|
6
|
+
"0.2.5": {
|
|
7
|
+
"en": "Fix system.adapter config path; trim news for ioBroker E1032 (CI release)",
|
|
8
|
+
"de": "system.adapter-Konfig-Pfad repariert; News gekürzt für ioBroker E1032 (CI-Release)",
|
|
9
|
+
"ru": "Исправлен путь system.adapter; news сокращены для E1032 (CI release)",
|
|
10
|
+
"pt": "Corrigido caminho system.adapter; news reduzidas para E1032 (release CI)",
|
|
11
|
+
"nl": "system.adapter-pad gerepareerd; news ingekort voor E1032 (CI-release)",
|
|
12
|
+
"fr": "Chemin system.adapter corrigé ; news réduites pour E1032 (release CI)",
|
|
13
|
+
"it": "Percorso system.adapter corretto; news ridotte per E1032 (release CI)",
|
|
14
|
+
"es": "Ruta system.adapter corregida; news recortadas para E1032 (release CI)",
|
|
15
|
+
"pl": "Naprawiono ścieżkę system.adapter; news skrócone dla E1032 (release CI)",
|
|
16
|
+
"uk": "Виправлено шлях system.adapter; news скорочено для E1032 (CI release)",
|
|
17
|
+
"zh-cn": "修复 system.adapter 路径;精简 news 以通过 E1032(CI 发布)"
|
|
18
|
+
},
|
|
19
|
+
"0.2.4": {
|
|
20
|
+
"en": "Fix instance config path: use extendForeignObject for system.adapter (remove misplaced object)",
|
|
21
|
+
"de": "Instanz-Konfig-Pfad repariert: extendForeignObject für system.adapter (falsches Objekt entfernen)",
|
|
22
|
+
"ru": "Исправлен путь конфигурации: extendForeignObject для system.adapter (удалён ошибочный объект)",
|
|
23
|
+
"pt": "Corrigido caminho de config: extendForeignObject para system.adapter (remove objeto incorreto)",
|
|
24
|
+
"nl": "Instance-configpad gerepareerd: extendForeignObject voor system.adapter (verkeerd object verwijderd)",
|
|
25
|
+
"fr": "Chemin config instance corrigé : extendForeignObject pour system.adapter (supprime objet incorrect)",
|
|
26
|
+
"it": "Percorso config istanza corretto: extendForeignObject per system.adapter (rimuove oggetto errato)",
|
|
27
|
+
"es": "Ruta de config corregida: extendForeignObject para system.adapter (elimina objeto incorrecto)",
|
|
28
|
+
"pl": "Naprawiono ścieżkę konfiguracji: extendForeignObject dla system.adapter (usuwa błędny obiekt)",
|
|
29
|
+
"uk": "Виправлено шлях конфігурації: extendForeignObject для system.adapter (видаляє помилковий об'єкт)",
|
|
30
|
+
"zh-cn": "修复实例配置路径:对 system.adapter 使用 extendForeignObject(移除错误对象)"
|
|
31
|
+
},
|
|
32
|
+
"0.2.3": {
|
|
33
|
+
"en": "Fix timer duration role: level.timer (writable), value.timer for remaining/elapsed",
|
|
34
|
+
"de": "Timer-Rolle korrigiert: level.timer (schreibbar), value.timer für remaining/elapsed",
|
|
35
|
+
"ru": "Исправлена роль таймера: level.timer (запись), value.timer для remaining/elapsed",
|
|
36
|
+
"pt": "Corrigida role do timer: level.timer (gravável), value.timer para remaining/elapsed",
|
|
37
|
+
"nl": "Timer-rol gecorrigeerd: level.timer (schrijfbaar), value.timer voor remaining/elapsed",
|
|
38
|
+
"fr": "Rôle timer corrigé : level.timer (écriture), value.timer pour remaining/elapsed",
|
|
39
|
+
"it": "Ruolo timer corretto: level.timer (scrivibile), value.timer per remaining/elapsed",
|
|
40
|
+
"es": "Rol timer corregido: level.timer (escribible), value.timer para remaining/elapsed",
|
|
41
|
+
"pl": "Poprawiono rolę timera: level.timer (zapis), value.timer dla remaining/elapsed",
|
|
42
|
+
"uk": "Виправлено роль таймера: level.timer (запис), value.timer для remaining/elapsed",
|
|
43
|
+
"zh-cn": "修复计时器角色:level.timer(可写),remaining/elapsed 用 value.timer"
|
|
44
|
+
},
|
|
6
45
|
"0.2.2": {
|
|
7
46
|
"en": "Fix object structure: timer channel, value.interval roles, button read flags",
|
|
8
47
|
"de": "Objektstruktur repariert: Timer-Kanal, value.interval-Rollen, Button read-Flags",
|
|
@@ -54,45 +93,6 @@
|
|
|
54
93
|
"pl": "Config: nowy piktogram po wybranym; duplikuj max. 3 równolegle",
|
|
55
94
|
"uk": "Config: новий піктограм після вибраного; дублювання макс. 3 паралельно",
|
|
56
95
|
"zh-cn": "Config:新象形图接所选项之后;复制最多 3 个并行"
|
|
57
|
-
},
|
|
58
|
-
"0.1.25": {
|
|
59
|
-
"en": "Fix Config schedule preview after save; allow 3 nested pictogram columns",
|
|
60
|
-
"de": "Config-Vorschau nach Speichern repariert; bis zu 3 verschachtelte Piktogramm-Spalten",
|
|
61
|
-
"ru": "Исправлен предпросмотр Config после сохранения; до 3 вложенных колонок",
|
|
62
|
-
"pt": "Corrigida pré-visualização Config após guardar; até 3 colunas aninhadas",
|
|
63
|
-
"nl": "Config-voorbeeld na opslaan gerepareerd; tot 3 geneste kolommen",
|
|
64
|
-
"fr": "Aperçu Config après enregistrement corrigé ; jusqu'à 3 colonnes imbriquées",
|
|
65
|
-
"it": "Anteprima Config dopo salvataggio corretta; fino a 3 colonne annidate",
|
|
66
|
-
"es": "Vista previa Config tras guardar corregida; hasta 3 columnas anidadas",
|
|
67
|
-
"pl": "Podgląd Config po zapisie naprawiony; do 3 zagnieżdżonych kolumn",
|
|
68
|
-
"uk": "Виправлено попередній перегляд Config після збереження; до 3 вкладених колонок",
|
|
69
|
-
"zh-cn": "修复 Config 保存后预览;最多 3 列嵌套象形图"
|
|
70
|
-
},
|
|
71
|
-
"0.1.24": {
|
|
72
|
-
"en": "Sun/moon pictograms on the day-period time bar in Live and Config schedule widgets",
|
|
73
|
-
"de": "Sonnen-/Mond-Piktogramme auf der Tagesbereich-Leiste in Live- und Config-Ablaufplan",
|
|
74
|
-
"ru": "Пиктограммы солнца/луны на шкале периодов дня в Live и Config",
|
|
75
|
-
"pt": "Pictogramas sol/lua na barra de períodos do dia em Live e Config",
|
|
76
|
-
"nl": "Zon/maan-pictogrammen op dagperiode-balk in Live en Config",
|
|
77
|
-
"fr": "Pictogrammes soleil/lune sur la barre des périodes en Live et Config",
|
|
78
|
-
"it": "Pittogrammi sole/luna sulla barra periodi in Live e Config",
|
|
79
|
-
"es": "Pictogramas sol/luna en la barra de periodos del día en Live y Config",
|
|
80
|
-
"pl": "Piktogramy słońca/księżyca na pasku okresów dnia w Live i Config",
|
|
81
|
-
"uk": "Піктограми сонця/місяця на смузі періодів дня в Live і Config",
|
|
82
|
-
"zh-cn": "Live 与 Config 日程条上的日月象形图"
|
|
83
|
-
},
|
|
84
|
-
"0.1.23": {
|
|
85
|
-
"en": "Fix custom pictogram preview: encode vis-2 path (spaces/umlauts) and /files fallback",
|
|
86
|
-
"de": "Piktogramm-Vorschau repariert: vis-2-Pfad kodieren (Leerzeichen/Umlaute) und /files-Fallback",
|
|
87
|
-
"ru": "Исправлен предпросмотр pictogram: кодирование пути vis-2 и fallback /files",
|
|
88
|
-
"pt": "Pré-visualização pictograma corrigida: codificar caminho vis-2 e fallback /files",
|
|
89
|
-
"nl": "Pictogram-voorbeeld gerepareerd: vis-2-pad coderen en /files-fallback",
|
|
90
|
-
"fr": "Aperçu pictogramme corrigé : encoder le chemin vis-2 et repli /files",
|
|
91
|
-
"it": "Anteprima pittogramma corretta: codifica percorso vis-2 e fallback /files",
|
|
92
|
-
"es": "Vista previa pictograma corregida: codificar ruta vis-2 y fallback /files",
|
|
93
|
-
"pl": "Podgląd piktogramu naprawiony: kodowanie ścieżki vis-2 i fallback /files",
|
|
94
|
-
"uk": "Виправлено попередній перегляд піктограм: кодування шляху vis-2 і fallback /files",
|
|
95
|
-
"zh-cn": "修复自定义象形图预览:编码 vis-2 路径与 /files 回退"
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
98
|
"titleLang": {
|