iobroker.webuntis2 0.1.0 → 0.1.1
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.de.md +4 -0
- package/README.md +7 -1
- package/build/lib/webuntis/Timetable.js +11 -2
- package/build/lib/webuntis/Timetable.js.map +2 -2
- package/build/main.js +73 -23
- package/build/main.js.map +2 -2
- package/io-package.json +15 -2
- package/package.json +1 -1
package/README.de.md
CHANGED
|
@@ -74,6 +74,10 @@ nicht vertrauliche Logmeldungen.
|
|
|
74
74
|
|
|
75
75
|
## Änderungsverlauf
|
|
76
76
|
|
|
77
|
+
### 0.1.1 (2026-09-12)
|
|
78
|
+
|
|
79
|
+
- (@Voodoo2man) Verbesserte rollierende Sieben-Tage-Ansicht und Wochentagszusammenfassungen ergänzt. Datumsfelder enthalten jetzt reine Datumswerte sowie zusätzliche Unix-Zeitstempel in Millisekunden.
|
|
80
|
+
|
|
77
81
|
### 0.1.0 (2026-09-11)
|
|
78
82
|
|
|
79
83
|
- (@Voodoo2man) Vollständige Funktionsveröffentlichung mit Stundenplandaten, Ferienterminen, verständlichen Stundennamen, Tagesübersichten, Informationen zur aktuellen und nächsten Stunde sowie React-Administrationsoberfläche.
|
package/README.md
CHANGED
|
@@ -69,6 +69,12 @@ and include only relevant, non-sensitive log messages when asking for help.
|
|
|
69
69
|
|
|
70
70
|
## Changelog
|
|
71
71
|
|
|
72
|
+
### 0.1.1 (2026-09-12)
|
|
73
|
+
|
|
74
|
+
- (@Voodoo2man) Improved the rolling seven-day timetable and added weekly summary states. Date fields now contain date-only values and companion Unix timestamps in milliseconds.
|
|
75
|
+
|
|
76
|
+
For earlier releases, see [CHANGELOG_OLD.md](CHANGELOG_OLD.md).
|
|
77
|
+
|
|
72
78
|
### 0.1.0 (2026-09-11)
|
|
73
79
|
|
|
74
80
|
- (@Voodoo2man) Complete feature release with timetable data, holidays, readable lesson names, daily summaries, current and next lesson information, and the React administration interface.
|
|
@@ -87,4 +93,4 @@ and include only relevant, non-sensitive log messages when asking for help.
|
|
|
87
93
|
|
|
88
94
|
Copyright (c) 2026 Voodoo2man <Voodoo2man@outlook.de>
|
|
89
95
|
|
|
90
|
-
MIT License. See [LICENSE](LICENSE).
|
|
96
|
+
MIT License. See [LICENSE](LICENSE).
|
|
@@ -22,6 +22,7 @@ __export(Timetable_exports, {
|
|
|
22
22
|
dateNumber: () => dateNumber,
|
|
23
23
|
dayRange: () => dayRange,
|
|
24
24
|
lessonChannelName: () => lessonChannelName,
|
|
25
|
+
nextWeekday: () => nextWeekday,
|
|
25
26
|
normalizeLesson: () => normalizeLesson,
|
|
26
27
|
normalizeLessons: () => normalizeLessons,
|
|
27
28
|
resolveTimetableReferences: () => resolveTimetableReferences,
|
|
@@ -167,14 +168,21 @@ function dateNumber(date) {
|
|
|
167
168
|
`${date.getFullYear()}${String(date.getMonth() + 1).padStart(2, "0")}${String(date.getDate()).padStart(2, "0")}`
|
|
168
169
|
);
|
|
169
170
|
}
|
|
171
|
+
function nextWeekday(date, targetWeekday) {
|
|
172
|
+
const result = new Date(date);
|
|
173
|
+
result.setHours(12, 0, 0, 0);
|
|
174
|
+
const currentWeekday = (result.getDay() + 6) % 7;
|
|
175
|
+
result.setDate(result.getDate() + (targetWeekday - currentWeekday + 7) % 7);
|
|
176
|
+
return result;
|
|
177
|
+
}
|
|
170
178
|
function dayRange(date) {
|
|
171
179
|
return { startDate: dateNumber(date), endDate: dateNumber(date) };
|
|
172
180
|
}
|
|
173
181
|
function weekRange(date) {
|
|
174
182
|
const start = new Date(date);
|
|
175
|
-
start.
|
|
183
|
+
start.setHours(12, 0, 0, 0);
|
|
176
184
|
const end = new Date(start);
|
|
177
|
-
end.setDate(
|
|
185
|
+
end.setDate(end.getDate() + 6);
|
|
178
186
|
return { startDate: dateNumber(start), endDate: dateNumber(end) };
|
|
179
187
|
}
|
|
180
188
|
function splitTimetable(lessons, today) {
|
|
@@ -200,6 +208,7 @@ function assertTimetableResponse(value) {
|
|
|
200
208
|
dateNumber,
|
|
201
209
|
dayRange,
|
|
202
210
|
lessonChannelName,
|
|
211
|
+
nextWeekday,
|
|
203
212
|
normalizeLesson,
|
|
204
213
|
normalizeLessons,
|
|
205
214
|
resolveTimetableReferences,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/webuntis/Timetable.ts"],
|
|
4
|
-
"sourcesContent": ["/* eslint-disable jsdoc/require-jsdoc, jsdoc/require-param, jsdoc/no-blank-blocks */\n\nimport { createHash } from \"node:crypto\";\nimport { WebUntisError } from \"./WebUntisErrors\";\nimport type { WebUntisPeriod } from \"./WebUntisTypes\";\n\n/**\n *\n */\nexport interface TimetableLesson {\n\t/**\n\t *\n\t */\n\tid: string;\n\t/**\n\t *\n\t */\n\tdate: string;\n\t/**\n\t *\n\t */\n\tstartTime: string;\n\t/**\n\t *\n\t */\n\tendTime: string;\n\t/**\n\t *\n\t */\n\tsubject: string;\n\t/**\n\t *\n\t */\n\tsubjectLong: string;\n\t/**\n\t *\n\t */\n\tteacher: string;\n\t/**\n\t *\n\t */\n\troom: string;\n\t/**\n\t *\n\t */\n\tclass: string;\n\t/**\n\t *\n\t */\n\tlessonId: number | null;\n\t/**\n\t *\n\t */\n\tperiodId: number | null;\n\t/**\n\t *\n\t */\n\tstatus: string;\n\t/**\n\t *\n\t */\n\tchanged: boolean;\n\t/**\n\t *\n\t */\n\tcancelled: boolean;\n\t/**\n\t *\n\t */\n\tsubstitution: string;\n\t/**\n\t *\n\t */\n\toriginalTeacher: string;\n\t/**\n\t *\n\t */\n\toriginalRoom: string;\n\t/**\n\t *\n\t */\n\toriginalSubject: string;\n}\n\nexport interface TimetableSummary {\n\thasSchool: boolean;\n\tlessonCount: number;\n\tlessonDurationMinutes: number;\n\tschoolStart: string;\n\tschoolEnd: string;\n\tsubjects: string;\n\tsubjectCount: number;\n\tfirstSubject: string;\n\tlastSubject: string;\n\thasChanges: boolean;\n\tchangeCount: number;\n\tcancellationCount: number;\n}\n\nexport interface TimetableMasterData {\n\tsubjects: WebUntisPeriod[];\n\tteachers: WebUntisPeriod[];\n\trooms: WebUntisPeriod[];\n\tklassen: WebUntisPeriod[];\n}\n\nexport function lessonChannelName(lesson: TimetableLesson): string {\n\tconst time =\n\t\tlesson.startTime && lesson.endTime\n\t\t\t? `${lesson.startTime}\u2013${lesson.endTime}`\n\t\t\t: lesson.startTime || lesson.endTime;\n\treturn [time, lesson.subjectLong || lesson.subject, lesson.teacher, lesson.room]\n\t\t.map(value => value.trim())\n\t\t.filter(Boolean)\n\t\t.join(\" \u00B7 \");\n}\n\nfunction text(value: unknown): string {\n\treturn typeof value === \"string\" || typeof value === \"number\" ? String(value) : \"\";\n}\n\nfunction firstName(value: unknown, long = false): string {\n\tif (!Array.isArray(value) || !value.length || typeof value[0] !== \"object\" || value[0] === null) {\n\t\treturn \"\";\n\t}\n\tconst item = value[0] as Record<string, unknown>;\n\treturn text(item[long ? \"longname\" : \"name\"] ?? item.longName ?? item.name);\n}\n\nfunction dateString(value: unknown): string {\n\tconst raw = text(value);\n\tif (/^\\d{8}$/.test(raw)) {\n\t\treturn `${raw.slice(0, 4)}-${raw.slice(4, 6)}-${raw.slice(6)}`;\n\t}\n\treturn raw;\n}\n\nfunction timeString(value: unknown): string {\n\tconst raw = text(value).padStart(4, \"0\");\n\treturn /^\\d{4}$/.test(raw) ? `${raw.slice(0, 2)}:${raw.slice(2)}` : text(value);\n}\n\nfunction bool(value: unknown): boolean {\n\treturn value === true || value === 1 || value === \"1\" || value === \"true\";\n}\n\nfunction stableId(period: WebUntisPeriod): string {\n\tconst id = period.id ?? period.lessonId ?? period.periodId;\n\tif (typeof id === \"number\" || typeof id === \"string\") {\n\t\treturn `period-${id}`;\n\t}\n\tconst key = [period.date, period.startTime, period.endTime, firstName(period.su), firstName(period.kl)].join(\"|\");\n\treturn `period-${createHash(\"sha1\").update(key).digest(\"hex\").slice(0, 16)}`;\n}\n\n/**\n *\n */\nexport function normalizeLesson(period: WebUntisPeriod): TimetableLesson {\n\tconst substitution = text(period.substText ?? period.substitution ?? period.subst);\n\tconst cancelled = bool(period.cancelled ?? period.isCancelled ?? period.cancelledLesson);\n\tconst changed =\n\t\tcancelled || Boolean(substitution) || Boolean(period.substTeacher ?? period.substRoom ?? period.substSubject);\n\treturn {\n\t\tid: stableId(period),\n\t\tdate: dateString(period.date),\n\t\tstartTime: timeString(period.startTime),\n\t\tendTime: timeString(period.endTime),\n\t\tsubject: firstName(period.su),\n\t\tsubjectLong: firstName(period.su, true),\n\t\tteacher: firstName(period.te),\n\t\troom: firstName(period.ro),\n\t\tclass: firstName(period.kl),\n\t\tlessonId: typeof period.id === \"number\" ? period.id : null,\n\t\tperiodId: typeof period.periodId === \"number\" ? period.periodId : null,\n\t\tstatus: text(period.activityType ?? period.status),\n\t\tchanged,\n\t\tcancelled,\n\t\tsubstitution,\n\t\toriginalTeacher: firstName(period.origTe ?? period.originalTeacher),\n\t\toriginalRoom: firstName(period.origRo ?? period.originalRoom),\n\t\toriginalSubject: firstName(period.origSu ?? period.originalSubject),\n\t};\n}\n\nfunction resolveReferences(value: unknown, masterData: WebUntisPeriod[]): unknown {\n\tif (!Array.isArray(value)) {\n\t\treturn value;\n\t}\n\tconst byId = new Map(\n\t\tmasterData.flatMap(item => {\n\t\t\tconst id = item.id ?? item.elementId;\n\t\t\treturn typeof id === \"string\" || typeof id === \"number\" ? [[String(id), item] as const] : [];\n\t\t}),\n\t);\n\treturn value.map(item => {\n\t\tif (typeof item !== \"object\" || item === null) {\n\t\t\treturn item;\n\t\t}\n\t\tconst id = (item as Record<string, unknown>).id;\n\t\treturn byId.get(String(id)) || item;\n\t});\n}\n\nexport function resolveTimetableReferences(\n\tperiods: WebUntisPeriod[],\n\tmasterData: TimetableMasterData,\n): WebUntisPeriod[] {\n\treturn periods.map(period => ({\n\t\t...period,\n\t\tkl: resolveReferences(period.kl, masterData.klassen),\n\t\tte: resolveReferences(period.te, masterData.teachers),\n\t\tsu: resolveReferences(period.su, masterData.subjects),\n\t\tro: resolveReferences(period.ro, masterData.rooms),\n\t\torigTe: resolveReferences(period.origTe, masterData.teachers),\n\t\torigRo: resolveReferences(period.origRo, masterData.rooms),\n\t\torigSu: resolveReferences(period.origSu, masterData.subjects),\n\t}));\n}\n\n/**\n *\n */\nexport function normalizeLessons(periods: WebUntisPeriod[]): TimetableLesson[] {\n\treturn periods\n\t\t.map(normalizeLesson)\n\t\t.sort((a, b) => `${a.date}${a.startTime}${a.id}`.localeCompare(`${b.date}${b.startTime}${b.id}`));\n}\n\nfunction durationMinutes(startTime: string, endTime: string): number {\n\tconst start = /^([0-9]{2}):([0-9]{2})$/.exec(startTime);\n\tconst end = /^([0-9]{2}):([0-9]{2})$/.exec(endTime);\n\tif (!start || !end) {\n\t\treturn 0;\n\t}\n\tconst startMinutes = Number(start[1]) * 60 + Number(start[2]);\n\tconst endMinutes = Number(end[1]) * 60 + Number(end[2]);\n\treturn Math.max(0, endMinutes - startMinutes);\n}\n\nexport function summarizeTimetable(lessons: TimetableLesson[]): TimetableSummary {\n\tconst subjects = lessons\n\t\t.map(lesson => lesson.subjectLong || lesson.subject)\n\t\t.filter((subject, index, values) => subject !== \"\" && values.indexOf(subject) === index);\n\treturn {\n\t\thasSchool: lessons.length > 0,\n\t\tlessonCount: lessons.length,\n\t\t// Cancelled lessons count as periods but have no actual teaching duration.\n\t\tlessonDurationMinutes: lessons.reduce(\n\t\t\t(total, lesson) => total + (lesson.cancelled ? 0 : durationMinutes(lesson.startTime, lesson.endTime)),\n\t\t\t0,\n\t\t),\n\t\tschoolStart: lessons[0]?.startTime || \"\",\n\t\tschoolEnd: lessons.at(-1)?.endTime || \"\",\n\t\tsubjects: subjects.join(\", \"),\n\t\tsubjectCount: subjects.length,\n\t\tfirstSubject: lessons[0]?.subjectLong || lessons[0]?.subject || \"\",\n\t\tlastSubject: lessons.at(-1)?.subjectLong || lessons.at(-1)?.subject || \"\",\n\t\thasChanges: lessons.some(lesson => lesson.changed || Boolean(lesson.substitution)),\n\t\tchangeCount: lessons.filter(lesson => lesson.changed || Boolean(lesson.substitution)).length,\n\t\tcancellationCount: lessons.filter(lesson => lesson.cancelled).length,\n\t};\n}\n\n/**\n *\n */\nexport function dateNumber(date: Date): number {\n\treturn Number(\n\t\t`${date.getFullYear()}${String(date.getMonth() + 1).padStart(2, \"0\")}${String(date.getDate()).padStart(2, \"0\")}`,\n\t);\n}\n\n/**\n *\n */\nexport function dayRange(date: Date): {\n\t/**\n\t *\n\t */\n\tstartDate: number;\n\t/**\n\t *\n\t */\n\tendDate: number;\n} {\n\treturn { startDate: dateNumber(date), endDate: dateNumber(date) };\n}\n\n/**\n *\n */\nexport function weekRange(date: Date): {\n\t/**\n\t *\n\t */\n\tstartDate: number;\n\t/**\n\t *\n\t */\n\tendDate: number;\n} {\n\tconst start = new Date(date);\n\tstart.
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["/* eslint-disable jsdoc/require-jsdoc, jsdoc/require-param, jsdoc/no-blank-blocks */\n\nimport { createHash } from \"node:crypto\";\nimport { WebUntisError } from \"./WebUntisErrors\";\nimport type { WebUntisPeriod } from \"./WebUntisTypes\";\n\n/**\n *\n */\nexport interface TimetableLesson {\n\t/**\n\t *\n\t */\n\tid: string;\n\t/**\n\t *\n\t */\n\tdate: string;\n\t/**\n\t *\n\t */\n\tstartTime: string;\n\t/**\n\t *\n\t */\n\tendTime: string;\n\t/**\n\t *\n\t */\n\tsubject: string;\n\t/**\n\t *\n\t */\n\tsubjectLong: string;\n\t/**\n\t *\n\t */\n\tteacher: string;\n\t/**\n\t *\n\t */\n\troom: string;\n\t/**\n\t *\n\t */\n\tclass: string;\n\t/**\n\t *\n\t */\n\tlessonId: number | null;\n\t/**\n\t *\n\t */\n\tperiodId: number | null;\n\t/**\n\t *\n\t */\n\tstatus: string;\n\t/**\n\t *\n\t */\n\tchanged: boolean;\n\t/**\n\t *\n\t */\n\tcancelled: boolean;\n\t/**\n\t *\n\t */\n\tsubstitution: string;\n\t/**\n\t *\n\t */\n\toriginalTeacher: string;\n\t/**\n\t *\n\t */\n\toriginalRoom: string;\n\t/**\n\t *\n\t */\n\toriginalSubject: string;\n}\n\nexport interface TimetableSummary {\n\thasSchool: boolean;\n\tlessonCount: number;\n\tlessonDurationMinutes: number;\n\tschoolStart: string;\n\tschoolEnd: string;\n\tsubjects: string;\n\tsubjectCount: number;\n\tfirstSubject: string;\n\tlastSubject: string;\n\thasChanges: boolean;\n\tchangeCount: number;\n\tcancellationCount: number;\n}\n\nexport interface TimetableMasterData {\n\tsubjects: WebUntisPeriod[];\n\tteachers: WebUntisPeriod[];\n\trooms: WebUntisPeriod[];\n\tklassen: WebUntisPeriod[];\n}\n\nexport function lessonChannelName(lesson: TimetableLesson): string {\n\tconst time =\n\t\tlesson.startTime && lesson.endTime\n\t\t\t? `${lesson.startTime}\u2013${lesson.endTime}`\n\t\t\t: lesson.startTime || lesson.endTime;\n\treturn [time, lesson.subjectLong || lesson.subject, lesson.teacher, lesson.room]\n\t\t.map(value => value.trim())\n\t\t.filter(Boolean)\n\t\t.join(\" \u00B7 \");\n}\n\nfunction text(value: unknown): string {\n\treturn typeof value === \"string\" || typeof value === \"number\" ? String(value) : \"\";\n}\n\nfunction firstName(value: unknown, long = false): string {\n\tif (!Array.isArray(value) || !value.length || typeof value[0] !== \"object\" || value[0] === null) {\n\t\treturn \"\";\n\t}\n\tconst item = value[0] as Record<string, unknown>;\n\treturn text(item[long ? \"longname\" : \"name\"] ?? item.longName ?? item.name);\n}\n\nfunction dateString(value: unknown): string {\n\tconst raw = text(value);\n\tif (/^\\d{8}$/.test(raw)) {\n\t\treturn `${raw.slice(0, 4)}-${raw.slice(4, 6)}-${raw.slice(6)}`;\n\t}\n\treturn raw;\n}\n\nfunction timeString(value: unknown): string {\n\tconst raw = text(value).padStart(4, \"0\");\n\treturn /^\\d{4}$/.test(raw) ? `${raw.slice(0, 2)}:${raw.slice(2)}` : text(value);\n}\n\nfunction bool(value: unknown): boolean {\n\treturn value === true || value === 1 || value === \"1\" || value === \"true\";\n}\n\nfunction stableId(period: WebUntisPeriod): string {\n\tconst id = period.id ?? period.lessonId ?? period.periodId;\n\tif (typeof id === \"number\" || typeof id === \"string\") {\n\t\treturn `period-${id}`;\n\t}\n\tconst key = [period.date, period.startTime, period.endTime, firstName(period.su), firstName(period.kl)].join(\"|\");\n\treturn `period-${createHash(\"sha1\").update(key).digest(\"hex\").slice(0, 16)}`;\n}\n\n/**\n *\n */\nexport function normalizeLesson(period: WebUntisPeriod): TimetableLesson {\n\tconst substitution = text(period.substText ?? period.substitution ?? period.subst);\n\tconst cancelled = bool(period.cancelled ?? period.isCancelled ?? period.cancelledLesson);\n\tconst changed =\n\t\tcancelled || Boolean(substitution) || Boolean(period.substTeacher ?? period.substRoom ?? period.substSubject);\n\treturn {\n\t\tid: stableId(period),\n\t\tdate: dateString(period.date),\n\t\tstartTime: timeString(period.startTime),\n\t\tendTime: timeString(period.endTime),\n\t\tsubject: firstName(period.su),\n\t\tsubjectLong: firstName(period.su, true),\n\t\tteacher: firstName(period.te),\n\t\troom: firstName(period.ro),\n\t\tclass: firstName(period.kl),\n\t\tlessonId: typeof period.id === \"number\" ? period.id : null,\n\t\tperiodId: typeof period.periodId === \"number\" ? period.periodId : null,\n\t\tstatus: text(period.activityType ?? period.status),\n\t\tchanged,\n\t\tcancelled,\n\t\tsubstitution,\n\t\toriginalTeacher: firstName(period.origTe ?? period.originalTeacher),\n\t\toriginalRoom: firstName(period.origRo ?? period.originalRoom),\n\t\toriginalSubject: firstName(period.origSu ?? period.originalSubject),\n\t};\n}\n\nfunction resolveReferences(value: unknown, masterData: WebUntisPeriod[]): unknown {\n\tif (!Array.isArray(value)) {\n\t\treturn value;\n\t}\n\tconst byId = new Map(\n\t\tmasterData.flatMap(item => {\n\t\t\tconst id = item.id ?? item.elementId;\n\t\t\treturn typeof id === \"string\" || typeof id === \"number\" ? [[String(id), item] as const] : [];\n\t\t}),\n\t);\n\treturn value.map(item => {\n\t\tif (typeof item !== \"object\" || item === null) {\n\t\t\treturn item;\n\t\t}\n\t\tconst id = (item as Record<string, unknown>).id;\n\t\treturn byId.get(String(id)) || item;\n\t});\n}\n\nexport function resolveTimetableReferences(\n\tperiods: WebUntisPeriod[],\n\tmasterData: TimetableMasterData,\n): WebUntisPeriod[] {\n\treturn periods.map(period => ({\n\t\t...period,\n\t\tkl: resolveReferences(period.kl, masterData.klassen),\n\t\tte: resolveReferences(period.te, masterData.teachers),\n\t\tsu: resolveReferences(period.su, masterData.subjects),\n\t\tro: resolveReferences(period.ro, masterData.rooms),\n\t\torigTe: resolveReferences(period.origTe, masterData.teachers),\n\t\torigRo: resolveReferences(period.origRo, masterData.rooms),\n\t\torigSu: resolveReferences(period.origSu, masterData.subjects),\n\t}));\n}\n\n/**\n *\n */\nexport function normalizeLessons(periods: WebUntisPeriod[]): TimetableLesson[] {\n\treturn periods\n\t\t.map(normalizeLesson)\n\t\t.sort((a, b) => `${a.date}${a.startTime}${a.id}`.localeCompare(`${b.date}${b.startTime}${b.id}`));\n}\n\nfunction durationMinutes(startTime: string, endTime: string): number {\n\tconst start = /^([0-9]{2}):([0-9]{2})$/.exec(startTime);\n\tconst end = /^([0-9]{2}):([0-9]{2})$/.exec(endTime);\n\tif (!start || !end) {\n\t\treturn 0;\n\t}\n\tconst startMinutes = Number(start[1]) * 60 + Number(start[2]);\n\tconst endMinutes = Number(end[1]) * 60 + Number(end[2]);\n\treturn Math.max(0, endMinutes - startMinutes);\n}\n\nexport function summarizeTimetable(lessons: TimetableLesson[]): TimetableSummary {\n\tconst subjects = lessons\n\t\t.map(lesson => lesson.subjectLong || lesson.subject)\n\t\t.filter((subject, index, values) => subject !== \"\" && values.indexOf(subject) === index);\n\treturn {\n\t\thasSchool: lessons.length > 0,\n\t\tlessonCount: lessons.length,\n\t\t// Cancelled lessons count as periods but have no actual teaching duration.\n\t\tlessonDurationMinutes: lessons.reduce(\n\t\t\t(total, lesson) => total + (lesson.cancelled ? 0 : durationMinutes(lesson.startTime, lesson.endTime)),\n\t\t\t0,\n\t\t),\n\t\tschoolStart: lessons[0]?.startTime || \"\",\n\t\tschoolEnd: lessons.at(-1)?.endTime || \"\",\n\t\tsubjects: subjects.join(\", \"),\n\t\tsubjectCount: subjects.length,\n\t\tfirstSubject: lessons[0]?.subjectLong || lessons[0]?.subject || \"\",\n\t\tlastSubject: lessons.at(-1)?.subjectLong || lessons.at(-1)?.subject || \"\",\n\t\thasChanges: lessons.some(lesson => lesson.changed || Boolean(lesson.substitution)),\n\t\tchangeCount: lessons.filter(lesson => lesson.changed || Boolean(lesson.substitution)).length,\n\t\tcancellationCount: lessons.filter(lesson => lesson.cancelled).length,\n\t};\n}\n\n/**\n *\n */\nexport function dateNumber(date: Date): number {\n\treturn Number(\n\t\t`${date.getFullYear()}${String(date.getMonth() + 1).padStart(2, \"0\")}${String(date.getDate()).padStart(2, \"0\")}`,\n\t);\n}\n\n/**\n * Returns the next date for a weekday, including today.\n */\nexport function nextWeekday(date: Date, targetWeekday: number): Date {\n\tconst result = new Date(date);\n\tresult.setHours(12, 0, 0, 0);\n\tconst currentWeekday = (result.getDay() + 6) % 7;\n\tresult.setDate(result.getDate() + ((targetWeekday - currentWeekday + 7) % 7));\n\treturn result;\n}\n\n/**\n *\n */\nexport function dayRange(date: Date): {\n\t/**\n\t *\n\t */\n\tstartDate: number;\n\t/**\n\t *\n\t */\n\tendDate: number;\n} {\n\treturn { startDate: dateNumber(date), endDate: dateNumber(date) };\n}\n\n/**\n *\n */\nexport function weekRange(date: Date): {\n\t/**\n\t *\n\t */\n\tstartDate: number;\n\t/**\n\t *\n\t */\n\tendDate: number;\n} {\n\tconst start = new Date(date);\n\tstart.setHours(12, 0, 0, 0);\n\tconst end = new Date(start);\n\tend.setDate(end.getDate() + 6);\n\treturn { startDate: dateNumber(start), endDate: dateNumber(end) };\n}\n\n/**\n *\n */\nexport function splitTimetable(\n\tlessons: TimetableLesson[],\n\ttoday: Date,\n): {\n\t/**\n\t *\n\t */\n\ttoday: TimetableLesson[];\n\t/**\n\t *\n\t */\n\ttomorrow: TimetableLesson[];\n\t/**\n\t *\n\t */\n\tweek: TimetableLesson[];\n} {\n\tconst todayKey = dateNumber(today).toString();\n\tconst tomorrow = new Date(today);\n\ttomorrow.setDate(today.getDate() + 1);\n\tconst tomorrowKey = dateNumber(tomorrow).toString();\n\tconst dateKey = (value: string): string => value.replaceAll(\"-\", \"\");\n\treturn {\n\t\ttoday: lessons.filter(lesson => dateKey(lesson.date) === todayKey),\n\t\ttomorrow: lessons.filter(lesson => dateKey(lesson.date) === tomorrowKey),\n\t\tweek: lessons,\n\t};\n}\n\n/**\n *\n */\nexport function assertTimetableResponse(value: unknown): asserts value is WebUntisPeriod[] {\n\tif (!Array.isArray(value) || !value.every(period => typeof period === \"object\" && period !== null)) {\n\t\tthrow new WebUntisError(\"INVALID_RESPONSE\", \"Invalid WebUntis timetable result\");\n\t}\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/build/main.js
CHANGED
|
@@ -46,6 +46,7 @@ const SUMMARY_STATE_DEFINITIONS = {
|
|
|
46
46
|
};
|
|
47
47
|
const LESSON_STATE_NAMES = {
|
|
48
48
|
date: "Date",
|
|
49
|
+
dateTimestamp: "Date (Unix timestamp ms)",
|
|
49
50
|
startTime: "Lesson start",
|
|
50
51
|
endTime: "Lesson end",
|
|
51
52
|
subject: "Subject",
|
|
@@ -89,6 +90,13 @@ const CURRENT_NEXT_STATE_DEFINITIONS = {
|
|
|
89
90
|
unit: "min"
|
|
90
91
|
}
|
|
91
92
|
};
|
|
93
|
+
function dateOnly(value) {
|
|
94
|
+
return value.trim().split(/[T ]/, 1)[0] || "";
|
|
95
|
+
}
|
|
96
|
+
function numericDate(value) {
|
|
97
|
+
const [year, month, day] = dateOnly(value).split("-").map(Number);
|
|
98
|
+
return year && month && day ? new Date(year, month - 1, day).getTime() : 0;
|
|
99
|
+
}
|
|
92
100
|
class WebuntisNext extends utils.Adapter {
|
|
93
101
|
webUntis;
|
|
94
102
|
timetableTimer;
|
|
@@ -149,7 +157,7 @@ class WebuntisNext extends utils.Adapter {
|
|
|
149
157
|
await this.setState("info.lastSuccessfulUpdate", now.toISOString(), true);
|
|
150
158
|
await this.setState("info.nextUpdate", new Date(now.getTime() + TIMETABLE_INTERVAL_MS).toISOString(), true);
|
|
151
159
|
await this.setState("info.connection", true, true);
|
|
152
|
-
this.log.
|
|
160
|
+
this.log.debug(`Timetable updated: ${updated} lessons updated, ${removed} obsolete lessons removed`);
|
|
153
161
|
} catch (error) {
|
|
154
162
|
await this.setState("info.connection", false, true);
|
|
155
163
|
await this.setState("info.nextUpdate", new Date(Date.now() + TIMETABLE_INTERVAL_MS).toISOString(), true);
|
|
@@ -202,31 +210,62 @@ class WebuntisNext extends utils.Adapter {
|
|
|
202
210
|
);
|
|
203
211
|
await this.writeSimpleState(
|
|
204
212
|
"holidays.current.startDate",
|
|
205
|
-
summary.current.startDate,
|
|
213
|
+
dateOnly(summary.current.startDate),
|
|
206
214
|
"Start date",
|
|
207
215
|
"string",
|
|
208
|
-
"
|
|
216
|
+
"text",
|
|
209
217
|
""
|
|
210
218
|
);
|
|
219
|
+
await this.writeSimpleState(
|
|
220
|
+
"holidays.current.startDateTimestamp",
|
|
221
|
+
numericDate(summary.current.startDate),
|
|
222
|
+
"Start date (Unix timestamp ms)",
|
|
223
|
+
"number",
|
|
224
|
+
"value",
|
|
225
|
+
0
|
|
226
|
+
);
|
|
211
227
|
await this.writeSimpleState(
|
|
212
228
|
"holidays.current.endDate",
|
|
213
|
-
summary.current.endDate,
|
|
229
|
+
dateOnly(summary.current.endDate),
|
|
214
230
|
"End date",
|
|
215
231
|
"string",
|
|
216
|
-
"
|
|
232
|
+
"text",
|
|
217
233
|
""
|
|
218
234
|
);
|
|
235
|
+
await this.writeSimpleState(
|
|
236
|
+
"holidays.current.endDateTimestamp",
|
|
237
|
+
numericDate(summary.current.endDate),
|
|
238
|
+
"End date (Unix timestamp ms)",
|
|
239
|
+
"number",
|
|
240
|
+
"value",
|
|
241
|
+
0
|
|
242
|
+
);
|
|
219
243
|
await this.writeSimpleState("holidays.next.name", summary.next.name, "Name", "string", "text", "");
|
|
220
244
|
await this.writeSimpleState("holidays.next.longName", summary.next.longName, "Long name", "string", "text", "");
|
|
221
245
|
await this.writeSimpleState(
|
|
222
246
|
"holidays.next.startDate",
|
|
223
|
-
summary.next.startDate,
|
|
247
|
+
dateOnly(summary.next.startDate),
|
|
224
248
|
"Start date",
|
|
225
249
|
"string",
|
|
226
|
-
"
|
|
250
|
+
"text",
|
|
251
|
+
""
|
|
252
|
+
);
|
|
253
|
+
await this.writeSimpleState(
|
|
254
|
+
"holidays.next.startDateTimestamp",
|
|
255
|
+
numericDate(summary.next.startDate),
|
|
256
|
+
"Start date (Unix timestamp ms)",
|
|
257
|
+
"number",
|
|
258
|
+
"value",
|
|
259
|
+
0
|
|
260
|
+
);
|
|
261
|
+
await this.writeSimpleState(
|
|
262
|
+
"holidays.next.endDate",
|
|
263
|
+
dateOnly(summary.next.endDate),
|
|
264
|
+
"End date",
|
|
265
|
+
"string",
|
|
266
|
+
"text",
|
|
227
267
|
""
|
|
228
268
|
);
|
|
229
|
-
await this.writeSimpleState("holidays.next.endDate", summary.next.endDate, "End date", "string", "date", "");
|
|
230
269
|
await this.writeSimpleState(
|
|
231
270
|
"holidays.next.daysUntil",
|
|
232
271
|
summary.next.daysUntil,
|
|
@@ -235,6 +274,14 @@ class WebuntisNext extends utils.Adapter {
|
|
|
235
274
|
"value",
|
|
236
275
|
0
|
|
237
276
|
);
|
|
277
|
+
await this.writeSimpleState(
|
|
278
|
+
"holidays.next.endDateTimestamp",
|
|
279
|
+
numericDate(summary.next.endDate),
|
|
280
|
+
"End date (Unix timestamp ms)",
|
|
281
|
+
"number",
|
|
282
|
+
"value",
|
|
283
|
+
0
|
|
284
|
+
);
|
|
238
285
|
}
|
|
239
286
|
async writeDaySummary(path, summary) {
|
|
240
287
|
for (const [name, definition] of Object.entries(SUMMARY_STATE_DEFINITIONS)) {
|
|
@@ -312,18 +359,17 @@ class WebuntisNext extends utils.Adapter {
|
|
|
312
359
|
let removed = await this.removeLegacyLessons(group);
|
|
313
360
|
if (group === "week") {
|
|
314
361
|
const weekdayNames = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"];
|
|
315
|
-
const byDay = weekdayNames.map(
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
})
|
|
320
|
-
);
|
|
362
|
+
const byDay = weekdayNames.map((_, index) => {
|
|
363
|
+
const targetDate = this.timetableDate((0, import_Timetable.nextWeekday)(now, index));
|
|
364
|
+
return lessons.filter((lesson) => lesson.date === targetDate);
|
|
365
|
+
});
|
|
321
366
|
for (let index = 0; index < weekdayNames.length; index++) {
|
|
322
367
|
const result = await this.writeTimetableDay(
|
|
323
368
|
`timetable.week.${weekdayNames[index]}`,
|
|
324
369
|
byDay[index],
|
|
325
|
-
this.timetableDate(
|
|
370
|
+
this.timetableDate((0, import_Timetable.nextWeekday)(now, index))
|
|
326
371
|
);
|
|
372
|
+
await this.writeDaySummary(`week.${weekdayNames[index]}`, (0, import_Timetable.summarizeTimetable)(byDay[index]));
|
|
327
373
|
removed += result.removed;
|
|
328
374
|
}
|
|
329
375
|
} else {
|
|
@@ -363,7 +409,15 @@ class WebuntisNext extends utils.Adapter {
|
|
|
363
409
|
common: { name: path.split(".").at(-1) || "Day" },
|
|
364
410
|
native: {}
|
|
365
411
|
});
|
|
366
|
-
await this.writeSimpleState(`${path}.date`, date, "Date", "string", "
|
|
412
|
+
await this.writeSimpleState(`${path}.date`, dateOnly(date), "Date", "string", "text", "");
|
|
413
|
+
await this.writeSimpleState(
|
|
414
|
+
`${path}.dateTimestamp`,
|
|
415
|
+
numericDate(date),
|
|
416
|
+
"Date (Unix timestamp ms)",
|
|
417
|
+
"number",
|
|
418
|
+
"value",
|
|
419
|
+
0
|
|
420
|
+
);
|
|
367
421
|
await this.writeSimpleState(`${path}.lessonCount`, lessons.length, "Lesson count", "number", "value", 0);
|
|
368
422
|
await this.setObjectNotExistsAsync(`${path}.lessons`, {
|
|
369
423
|
type: "channel",
|
|
@@ -390,12 +444,6 @@ class WebuntisNext extends utils.Adapter {
|
|
|
390
444
|
}
|
|
391
445
|
return { removed: stale.size };
|
|
392
446
|
}
|
|
393
|
-
getMonday(date, dayOffset) {
|
|
394
|
-
const monday = new Date(date);
|
|
395
|
-
monday.setHours(12, 0, 0, 0);
|
|
396
|
-
monday.setDate(monday.getDate() - (monday.getDay() + 6) % 7 + dayOffset);
|
|
397
|
-
return monday;
|
|
398
|
-
}
|
|
399
447
|
timetableDate(date) {
|
|
400
448
|
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
|
|
401
449
|
}
|
|
@@ -405,6 +453,7 @@ class WebuntisNext extends utils.Adapter {
|
|
|
405
453
|
common: { name, type, role, read: true, write: false, def },
|
|
406
454
|
native: {}
|
|
407
455
|
});
|
|
456
|
+
await this.extendObjectAsync(id, { common: { name, type, role, read: true, write: false, def } });
|
|
408
457
|
await this.setStateAsync(id, value, true);
|
|
409
458
|
}
|
|
410
459
|
async writeLesson(path, slot, lesson) {
|
|
@@ -417,7 +466,8 @@ class WebuntisNext extends utils.Adapter {
|
|
|
417
466
|
});
|
|
418
467
|
await this.extendObjectAsync(base, { common: { name: label || `Lesson ${slot}` } });
|
|
419
468
|
const values = {
|
|
420
|
-
date: { value: lesson.date, type: "string", role: "
|
|
469
|
+
date: { value: dateOnly(lesson.date), type: "string", role: "text" },
|
|
470
|
+
dateTimestamp: { value: numericDate(lesson.date), type: "number", role: "value" },
|
|
421
471
|
startTime: { value: lesson.startTime, type: "string", role: "text" },
|
|
422
472
|
endTime: { value: lesson.endTime, type: "string", role: "text" },
|
|
423
473
|
subject: { value: lesson.subject, type: "string", role: "text" },
|
package/build/main.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/main.ts"],
|
|
4
|
-
"sourcesContent": ["import * as utils from \"@iobroker/adapter-core\";\nimport { WebUntisService, type WebUntisConnectionConfig } from \"./lib/webuntis/WebUntisService\";\nimport { cleanupLegacyNamespace } from \"./lib/LegacyNamespaceCleanup\";\nimport type { HolidaySummary } from \"./lib/webuntis/Holidays\";\nimport { WebUntisError } from \"./lib/webuntis/WebUntisErrors\";\nimport {\n\tlessonChannelName,\n\tsummarizeTimetable,\n\ttype TimetableLesson,\n\ttype TimetableSummary,\n} from \"./lib/webuntis/Timetable\";\nimport type { WebUntisHttpDiagnostic } from \"./lib/webuntis/WebUntisTypes\";\nimport { deriveCurrentNextLesson, type CurrentNextLessonSummary } from \"./lib/webuntis/CurrentNextLesson\";\n\nconst TIMETABLE_INTERVAL_MS = 5 * 60 * 1000;\nconst CURRENT_NEXT_INTERVAL_MS = 60 * 1000;\nconst TIMETABLE_GROUPS = [\"today\", \"tomorrow\", \"week\"] as const;\ntype TimetableGroup = (typeof TIMETABLE_GROUPS)[number];\n\nconst SUMMARY_STATE_DEFINITIONS: Record<\n\tkeyof TimetableSummary,\n\t{ type: \"string\" | \"number\" | \"boolean\"; role: string; name: string; def: string | number | boolean }\n> = {\n\thasSchool: { type: \"boolean\", role: \"indicator\", name: \"Has school\", def: false },\n\tlessonCount: { type: \"number\", role: \"value\", name: \"Lesson count\", def: 0 },\n\tlessonDurationMinutes: { type: \"number\", role: \"value\", name: \"Lesson duration in minutes\", def: 0 },\n\tschoolStart: { type: \"string\", role: \"text\", name: \"School start\", def: \"\" },\n\tschoolEnd: { type: \"string\", role: \"text\", name: \"School end\", def: \"\" },\n\tsubjects: { type: \"string\", role: \"text\", name: \"Subjects\", def: \"\" },\n\tsubjectCount: { type: \"number\", role: \"value\", name: \"Subject count\", def: 0 },\n\tfirstSubject: { type: \"string\", role: \"text\", name: \"First subject\", def: \"\" },\n\tlastSubject: { type: \"string\", role: \"text\", name: \"Last subject\", def: \"\" },\n\thasChanges: { type: \"boolean\", role: \"indicator\", name: \"Has changes\", def: false },\n\tchangeCount: { type: \"number\", role: \"value\", name: \"Change count\", def: 0 },\n\tcancellationCount: { type: \"number\", role: \"value\", name: \"Cancellation count\", def: 0 },\n};\n\nconst LESSON_STATE_NAMES: Record<string, string> = {\n\tdate: \"Date\",\n\tstartTime: \"Lesson start\",\n\tendTime: \"Lesson end\",\n\tsubject: \"Subject\",\n\tsubjectLong: \"Subject name\",\n\tteacher: \"Teacher\",\n\troom: \"Room\",\n\tclass: \"Class\",\n\tlessonId: \"WebUntis lesson ID\",\n\tperiodId: \"WebUntis period ID\",\n\tstatus: \"Lesson status\",\n\tchanged: \"Lesson changed\",\n\tcancelled: \"Lesson cancelled\",\n\tsubstitution: \"Substitution\",\n\toriginalTeacher: \"Original teacher\",\n\toriginalRoom: \"Original room\",\n\toriginalSubject: \"Original subject\",\n};\n\nconst CURRENT_NEXT_STATE_DEFINITIONS: Record<\n\tkeyof CurrentNextLessonSummary,\n\t{ type: \"string\" | \"number\" | \"boolean\"; role: string; name: string; def: string | number | boolean; unit?: string }\n> = {\n\tcurrentLesson: { type: \"string\", role: \"text\", name: \"Current lesson\", def: \"\" },\n\tcurrentSubject: { type: \"string\", role: \"text\", name: \"Current subject\", def: \"\" },\n\tcurrentRoom: { type: \"string\", role: \"text\", name: \"Current room\", def: \"\" },\n\tcurrentTeacher: { type: \"string\", role: \"text\", name: \"Current teacher\", def: \"\" },\n\tnextLesson: { type: \"string\", role: \"text\", name: \"Next lesson\", def: \"\" },\n\tnextSubject: { type: \"string\", role: \"text\", name: \"Next subject\", def: \"\" },\n\tnextRoom: { type: \"string\", role: \"text\", name: \"Next room\", def: \"\" },\n\tnextTeacher: { type: \"string\", role: \"text\", name: \"Next teacher\", def: \"\" },\n\tnextLessonStart: { type: \"string\", role: \"text\", name: \"Next lesson start\", def: \"\" },\n\tminutesUntilNextLesson: {\n\t\ttype: \"number\",\n\t\trole: \"value.interval\",\n\t\tname: \"Minutes until next lesson\",\n\t\tdef: 0,\n\t\tunit: \"min\",\n\t},\n\tschoolRunning: { type: \"boolean\", role: \"indicator\", name: \"School running\", def: false },\n\tminutesUntilSchoolEnd: {\n\t\ttype: \"number\",\n\t\trole: \"value.interval\",\n\t\tname: \"Minutes until school end\",\n\t\tdef: 0,\n\t\tunit: \"min\",\n\t},\n};\n\nclass WebuntisNext extends utils.Adapter {\n\tprivate readonly webUntis: WebUntisService;\n\tprivate timetableTimer?: ioBroker.Interval;\n\tprivate currentNextTimer?: ioBroker.Interval;\n\tprivate todayLessons: TimetableLesson[] = [];\n\n\tpublic constructor(options: Partial<utils.AdapterOptions> = {}) {\n\t\tsuper({ ...options, name: \"webuntis2\" });\n\t\tthis.webUntis = new WebUntisService(\n\t\t\tthis.logHttpDiagnostic.bind(this),\n\t\t\tmessage => this.log.info(message),\n\t\t\tmessage => this.log.warn(message),\n\t\t\tfetch,\n\t\t\tmessage => this.log.debug(message),\n\t\t);\n\t\tthis.on(\"ready\", this.onReady.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 logHttpDiagnostic(diagnostic: WebUntisHttpDiagnostic): void {\n\t\tthis.log.debug(`WebUntis ${diagnostic.method || \"request\"} HTTP ${JSON.stringify(diagnostic)}`);\n\t}\n\n\tprivate async onReady(): Promise<void> {\n\t\tawait this.setState(\"info.connection\", false, true);\n\t\tif (!this.hasConnectionConfig()) {\n\t\t\treturn;\n\t\t}\n\t\tawait this.updateTimetable();\n\t\tthis.timetableTimer = this.setInterval(() => void this.updateTimetable(), TIMETABLE_INTERVAL_MS);\n\t\tthis.currentNextTimer = this.setInterval(() => void this.updateCurrentNextStates(), CURRENT_NEXT_INTERVAL_MS);\n\t}\n\n\tprivate hasConnectionConfig(): this is { config: WebUntisConnectionConfig } {\n\t\treturn Boolean(\n\t\t\tthis.config.server &&\n\t\t\tthis.config.schoolName &&\n\t\t\ttypeof this.config.schoolId === \"number\" &&\n\t\t\tthis.config.username &&\n\t\t\tthis.config.password,\n\t\t);\n\t}\n\n\tprivate async updateTimetable(): Promise<void> {\n\t\tawait this.setState(\"info.lastUpdate\", new Date().toISOString(), true);\n\t\ttry {\n\t\t\tawait cleanupLegacyNamespace(this, \"messages\");\n\t\t\tawait this.ensureTimetableRoot();\n\t\t\tawait this.ensureHolidaysRoot();\n\t\t\tawait this.cleanupObsoleteStructure();\n\t\t\tconst now = new Date();\n\t\t\tconst data = await this.webUntis.loadTimetable(this.config, now);\n\t\t\tthis.todayLessons = data.today;\n\t\t\tlet updated = 0;\n\t\t\tlet removed = 0;\n\t\t\tfor (const group of TIMETABLE_GROUPS) {\n\t\t\t\tconst result = await this.writeTimetableGroup(group, data[group], now);\n\t\t\t\tupdated += result.updated;\n\t\t\t\tremoved += result.removed;\n\t\t\t}\n\t\t\tif (data.holidays) {\n\t\t\t\tawait this.writeHolidaySummary(data.holidays);\n\t\t\t} else {\n\t\t\t\tthis.log.warn(\"WebUntis holidays are not available; previous holiday values were preserved\");\n\t\t\t}\n\t\t\tawait this.setState(\"info.lastSuccessfulUpdate\", now.toISOString(), true);\n\t\t\tawait this.setState(\"info.nextUpdate\", new Date(now.getTime() + TIMETABLE_INTERVAL_MS).toISOString(), true);\n\t\t\tawait this.setState(\"info.connection\", true, true);\n\t\t\tthis.log.warn(`Timetable updated: ${updated} lessons updated, ${removed} obsolete lessons removed`);\n\t\t} catch (error) {\n\t\t\tawait this.setState(\"info.connection\", false, true);\n\t\t\tawait this.setState(\"info.nextUpdate\", new Date(Date.now() + TIMETABLE_INTERVAL_MS).toISOString(), true);\n\t\t\tconst code = error instanceof WebUntisError ? error.code : \"UNEXPECTED_RESPONSE\";\n\t\t\tconst detail = error instanceof Error ? ` (${error.message})` : \"\";\n\t\t\tthis.log.warn(`Timetable update failed: ${code}${detail}; existing timetable data was kept`);\n\t\t}\n\t}\n\n\tprivate async ensureTimetableRoot(): Promise<void> {\n\t\tawait this.setObjectNotExistsAsync(\"timetable\", {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: \"Timetable\" },\n\t\t\tnative: {},\n\t\t});\n\t}\n\n\tprivate async ensureHolidaysRoot(): Promise<void> {\n\t\tawait this.setObjectNotExistsAsync(\"holidays\", {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: \"Holidays\" },\n\t\t\tnative: {},\n\t\t});\n\t\tawait this.setObjectNotExistsAsync(\"holidays.current\", {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: \"Current holiday\" },\n\t\t\tnative: {},\n\t\t});\n\t\tawait this.setObjectNotExistsAsync(\"holidays.next\", {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: \"Next holiday\" },\n\t\t\tnative: {},\n\t\t});\n\t}\n\n\tprivate async writeHolidaySummary(summary: HolidaySummary): Promise<void> {\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.current.active\",\n\t\t\tsummary.current.active,\n\t\t\t\"Active\",\n\t\t\t\"boolean\",\n\t\t\t\"indicator\",\n\t\t\tfalse,\n\t\t);\n\t\tawait this.writeSimpleState(\"holidays.current.name\", summary.current.name, \"Name\", \"string\", \"text\", \"\");\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.current.longName\",\n\t\t\tsummary.current.longName,\n\t\t\t\"Long name\",\n\t\t\t\"string\",\n\t\t\t\"text\",\n\t\t\t\"\",\n\t\t);\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.current.startDate\",\n\t\t\tsummary.current.startDate,\n\t\t\t\"Start date\",\n\t\t\t\"string\",\n\t\t\t\"date\",\n\t\t\t\"\",\n\t\t);\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.current.endDate\",\n\t\t\tsummary.current.endDate,\n\t\t\t\"End date\",\n\t\t\t\"string\",\n\t\t\t\"date\",\n\t\t\t\"\",\n\t\t);\n\t\tawait this.writeSimpleState(\"holidays.next.name\", summary.next.name, \"Name\", \"string\", \"text\", \"\");\n\t\tawait this.writeSimpleState(\"holidays.next.longName\", summary.next.longName, \"Long name\", \"string\", \"text\", \"\");\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.next.startDate\",\n\t\t\tsummary.next.startDate,\n\t\t\t\"Start date\",\n\t\t\t\"string\",\n\t\t\t\"date\",\n\t\t\t\"\",\n\t\t);\n\t\tawait this.writeSimpleState(\"holidays.next.endDate\", summary.next.endDate, \"End date\", \"string\", \"date\", \"\");\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.next.daysUntil\",\n\t\t\tsummary.next.daysUntil,\n\t\t\t\"Days until\",\n\t\t\t\"number\",\n\t\t\t\"value\",\n\t\t\t0,\n\t\t);\n\t}\n\n\tprivate async writeDaySummary(path: string, summary: TimetableSummary): Promise<void> {\n\t\tfor (const [name, definition] of Object.entries(SUMMARY_STATE_DEFINITIONS) as [\n\t\t\tkeyof TimetableSummary,\n\t\t\t(typeof SUMMARY_STATE_DEFINITIONS)[keyof TimetableSummary],\n\t\t][]) {\n\t\t\tif (name === \"lessonCount\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tawait this.setObjectNotExistsAsync(`timetable.${path}.${name}`, {\n\t\t\t\ttype: \"state\",\n\t\t\t\tcommon: {\n\t\t\t\t\tname: definition.name,\n\t\t\t\t\ttype: definition.type,\n\t\t\t\t\trole: definition.role,\n\t\t\t\t\tread: true,\n\t\t\t\t\twrite: false,\n\t\t\t\t\tdef: definition.def,\n\t\t\t\t},\n\t\t\t\tnative: {},\n\t\t\t});\n\t\t\tawait this.extendObjectAsync(`timetable.${path}.${name}`, {\n\t\t\t\tcommon: { type: definition.type, role: definition.role, def: definition.def },\n\t\t\t});\n\t\t\tawait this.setStateAsync(`timetable.${path}.${name}`, summary[name], true);\n\t\t}\n\t}\n\n\tprivate async writeCurrentNextSummary(lessons: TimetableLesson[], now: Date): Promise<void> {\n\t\tconst summary = deriveCurrentNextLesson(lessons, now);\n\t\tfor (const [name, definition] of Object.entries(CURRENT_NEXT_STATE_DEFINITIONS) as [\n\t\t\tkeyof CurrentNextLessonSummary,\n\t\t\t(typeof CURRENT_NEXT_STATE_DEFINITIONS)[keyof CurrentNextLessonSummary],\n\t\t][]) {\n\t\t\tawait this.setObjectNotExistsAsync(`timetable.today.${name}`, {\n\t\t\t\ttype: \"state\",\n\t\t\t\tcommon: {\n\t\t\t\t\tname: definition.name,\n\t\t\t\t\ttype: definition.type,\n\t\t\t\t\trole: definition.role,\n\t\t\t\t\tread: true,\n\t\t\t\t\twrite: false,\n\t\t\t\t\tdef: definition.def,\n\t\t\t\t\t...(definition.unit ? { unit: definition.unit } : {}),\n\t\t\t\t},\n\t\t\t\tnative: {},\n\t\t\t});\n\t\t\tawait this.extendObjectAsync(`timetable.today.${name}`, {\n\t\t\t\tcommon: {\n\t\t\t\t\ttype: definition.type,\n\t\t\t\t\trole: definition.role,\n\t\t\t\t\tdef: definition.def,\n\t\t\t\t\t...(definition.unit ? { unit: definition.unit } : {}),\n\t\t\t\t},\n\t\t\t});\n\t\t\tawait this.setStateAsync(`timetable.today.${name}`, summary[name], true);\n\t\t}\n\t}\n\n\tprivate async updateCurrentNextStates(): Promise<void> {\n\t\tawait this.writeCurrentNextSummary(this.todayLessons, new Date());\n\t}\n\n\tprivate async cleanupObsoleteStructure(): Promise<void> {\n\t\tfor (const id of [\n\t\t\t\"info.timetable\",\n\t\t\t\"timetable.timetable\",\n\t\t\t\"timetable.today.count\",\n\t\t\t\"timetable.tomorrow.count\",\n\t\t\t\"timetable.today.subjectsJson\",\n\t\t\t\"timetable.tomorrow.subjectsJson\",\n\t\t]) {\n\t\t\tif (await this.getObjectAsync(id)) {\n\t\t\t\tawait this.delObjectAsync(id, { recursive: true });\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async writeTimetableGroup(\n\t\tgroup: TimetableGroup,\n\t\tlessons: TimetableLesson[],\n\t\tnow: Date,\n\t): Promise<{ updated: number; removed: number }> {\n\t\tawait this.setObjectNotExistsAsync(`timetable.${group}`, {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: `Timetable ${group}` },\n\t\t\tnative: {},\n\t\t});\n\t\tlet removed = await this.removeLegacyLessons(group);\n\t\tif (group === \"week\") {\n\t\t\tconst weekdayNames = [\"monday\", \"tuesday\", \"wednesday\", \"thursday\", \"friday\", \"saturday\", \"sunday\"];\n\t\t\tconst byDay = weekdayNames.map((_, index) =>\n\t\t\t\tlessons.filter(lesson => {\n\t\t\t\t\tconst date = new Date(`${lesson.date}T12:00:00`);\n\t\t\t\t\treturn (date.getDay() + 6) % 7 === index;\n\t\t\t\t}),\n\t\t\t);\n\t\t\tfor (let index = 0; index < weekdayNames.length; index++) {\n\t\t\t\tconst result = await this.writeTimetableDay(\n\t\t\t\t\t`timetable.week.${weekdayNames[index]}`,\n\t\t\t\t\tbyDay[index],\n\t\t\t\t\tthis.timetableDate(this.getMonday(now, index)),\n\t\t\t\t);\n\t\t\t\tremoved += result.removed;\n\t\t\t}\n\t\t} else {\n\t\t\tconst day = new Date(now);\n\t\t\tif (group === \"tomorrow\") {\n\t\t\t\tday.setDate(day.getDate() + 1);\n\t\t\t}\n\t\t\tconst result = await this.writeTimetableDay(`timetable.${group}`, lessons, this.timetableDate(day));\n\t\t\tawait this.writeDaySummary(group, summarizeTimetable(lessons));\n\t\t\tif (group === \"today\") {\n\t\t\t\tawait this.writeCurrentNextSummary(lessons, now);\n\t\t\t}\n\t\t\tremoved += result.removed;\n\t\t}\n\t\treturn { updated: lessons.length, removed };\n\t}\n\n\tprivate async removeLegacyLessons(group: TimetableGroup): Promise<number> {\n\t\tconst existing = await this.getObjectListAsync({\n\t\t\tstartkey: `${this.namespace}.timetable.${group}.`,\n\t\t\tendkey: `${this.namespace}.timetable.${group}.\\uffff`,\n\t\t});\n\t\tconst legacy = new Set<string>();\n\t\tfor (const object of existing.rows || []) {\n\t\t\tconst first = object.id.replace(`${this.namespace}.timetable.${group}.`, \"\").split(\".\")[0];\n\t\t\tif (first.startsWith(\"period-\")) {\n\t\t\t\tlegacy.add(first);\n\t\t\t}\n\t\t}\n\t\tfor (const id of legacy) {\n\t\t\tawait this.delObjectAsync(`timetable.${group}.${id}`, { recursive: true });\n\t\t}\n\t\treturn legacy.size;\n\t}\n\n\tprivate async writeTimetableDay(\n\t\tpath: string,\n\t\tlessons: TimetableLesson[],\n\t\tdate: string,\n\t): Promise<{ removed: number }> {\n\t\tawait this.setObjectNotExistsAsync(path, {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: path.split(\".\").at(-1) || \"Day\" },\n\t\t\tnative: {},\n\t\t});\n\t\tawait this.writeSimpleState(`${path}.date`, date, \"Date\", \"string\", \"date\", \"\");\n\t\tawait this.writeSimpleState(`${path}.lessonCount`, lessons.length, \"Lesson count\", \"number\", \"value\", 0);\n\t\tawait this.setObjectNotExistsAsync(`${path}.lessons`, {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: \"Lessons\" },\n\t\t\tnative: {},\n\t\t});\n\t\tconst expected = new Set(lessons.map((_lesson, index) => String(index + 1).padStart(2, \"0\")));\n\t\tconst existing = await this.getObjectListAsync({\n\t\t\tstartkey: `${this.namespace}.${path}.lessons.`,\n\t\t\tendkey: `${this.namespace}.${path}.lessons.\\uffff`,\n\t\t});\n\t\tconst stale = new Set<string>();\n\t\tfor (const object of existing.rows || []) {\n\t\t\tconst slot = object.id.replace(`${this.namespace}.${path}.lessons.`, \"\").split(\".\")[0];\n\t\t\tif (slot && !expected.has(slot)) {\n\t\t\t\tstale.add(slot);\n\t\t\t}\n\t\t}\n\t\tfor (const slot of stale) {\n\t\t\tawait this.delObjectAsync(`${path}.lessons.${slot}`, { recursive: true });\n\t\t}\n\t\tfor (const [index, lesson] of lessons.entries()) {\n\t\t\tawait this.writeLesson(path, String(index + 1).padStart(2, \"0\"), lesson);\n\t\t}\n\t\treturn { removed: stale.size };\n\t}\n\n\tprivate getMonday(date: Date, dayOffset: number): Date {\n\t\tconst monday = new Date(date);\n\t\tmonday.setHours(12, 0, 0, 0);\n\t\tmonday.setDate(monday.getDate() - ((monday.getDay() + 6) % 7) + dayOffset);\n\t\treturn monday;\n\t}\n\n\tprivate timetableDate(date: Date): string {\n\t\treturn `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, \"0\")}-${String(date.getDate()).padStart(2, \"0\")}`;\n\t}\n\n\tprivate async writeSimpleState(\n\t\tid: string,\n\t\tvalue: string | number | boolean,\n\t\tname: string,\n\t\ttype: \"string\" | \"number\" | \"boolean\",\n\t\trole: string,\n\t\tdef: string | number | boolean,\n\t): Promise<void> {\n\t\tawait this.setObjectNotExistsAsync(id, {\n\t\t\ttype: \"state\",\n\t\t\tcommon: { name, type, role, read: true, write: false, def },\n\t\t\tnative: {},\n\t\t});\n\t\tawait this.setStateAsync(id, value, true);\n\t}\n\n\tprivate async writeLesson(path: string, slot: string, lesson: TimetableLesson): Promise<void> {\n\t\tconst base = `${path}.lessons.${slot}`;\n\t\tconst label = lessonChannelName(lesson);\n\t\tawait this.setObjectNotExistsAsync(base, {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: label || `Lesson ${slot}` },\n\t\t\tnative: {},\n\t\t});\n\t\tawait this.extendObjectAsync(base, { common: { name: label || `Lesson ${slot}` } });\n\t\tconst values: Record<\n\t\t\tstring,\n\t\t\t{ value: string | number | boolean; type: \"string\" | \"number\" | \"boolean\"; role: string }\n\t\t> = {\n\t\t\tdate: { value: lesson.date, type: \"string\", role: \"date\" },\n\t\t\tstartTime: { value: lesson.startTime, type: \"string\", role: \"text\" },\n\t\t\tendTime: { value: lesson.endTime, type: \"string\", role: \"text\" },\n\t\t\tsubject: { value: lesson.subject, type: \"string\", role: \"text\" },\n\t\t\tsubjectLong: { value: lesson.subjectLong, type: \"string\", role: \"text\" },\n\t\t\tteacher: { value: lesson.teacher, type: \"string\", role: \"text\" },\n\t\t\troom: { value: lesson.room, type: \"string\", role: \"text\" },\n\t\t\tclass: { value: lesson.class, type: \"string\", role: \"text\" },\n\t\t\t...(lesson.lessonId === null\n\t\t\t\t? {}\n\t\t\t\t: { lessonId: { value: String(lesson.lessonId), type: \"string\" as const, role: \"text\" } }),\n\t\t\t...(lesson.periodId === null\n\t\t\t\t? {}\n\t\t\t\t: { periodId: { value: String(lesson.periodId), type: \"string\" as const, role: \"text\" } }),\n\t\t\tstatus: { value: lesson.status, type: \"string\", role: \"text\" },\n\t\t\tchanged: { value: lesson.changed, type: \"boolean\", role: \"indicator\" },\n\t\t\tcancelled: { value: lesson.cancelled, type: \"boolean\", role: \"indicator\" },\n\t\t\t...(lesson.substitution\n\t\t\t\t? { substitution: { value: lesson.substitution, type: \"string\" as const, role: \"text\" } }\n\t\t\t\t: {}),\n\t\t\t...(lesson.originalTeacher && lesson.originalTeacher !== lesson.teacher\n\t\t\t\t? { originalTeacher: { value: lesson.originalTeacher, type: \"string\" as const, role: \"text\" } }\n\t\t\t\t: {}),\n\t\t\t...(lesson.originalRoom && lesson.originalRoom !== lesson.room\n\t\t\t\t? { originalRoom: { value: lesson.originalRoom, type: \"string\" as const, role: \"text\" } }\n\t\t\t\t: {}),\n\t\t\t...(lesson.originalSubject && lesson.originalSubject !== lesson.subject\n\t\t\t\t? { originalSubject: { value: lesson.originalSubject, type: \"string\" as const, role: \"text\" } }\n\t\t\t\t: {}),\n\t\t};\n\t\tconst optional = [\"substitution\", \"originalTeacher\", \"originalRoom\", \"originalSubject\"];\n\t\tfor (const name of optional) {\n\t\t\tif (!(name in values) && (await this.getObjectAsync(`${base}.${name}`))) {\n\t\t\t\tawait this.delObjectAsync(`${base}.${name}`);\n\t\t\t}\n\t\t}\n\t\tfor (const [name, item] of Object.entries(values)) {\n\t\t\tawait this.setObjectNotExistsAsync(`${base}.${name}`, {\n\t\t\t\ttype: \"state\",\n\t\t\t\tcommon: {\n\t\t\t\t\tname: LESSON_STATE_NAMES[name] || name,\n\t\t\t\t\ttype: item.type,\n\t\t\t\t\trole: item.role,\n\t\t\t\t\tread: true,\n\t\t\t\t\twrite: false,\n\t\t\t\t\tdef: item.value,\n\t\t\t\t},\n\t\t\t\tnative: {},\n\t\t\t});\n\t\t\tawait this.extendObjectAsync(`${base}.${name}`, {\n\t\t\t\tcommon: { name: LESSON_STATE_NAMES[name] || name, type: item.type, role: item.role, def: item.value },\n\t\t\t});\n\t\t\tawait this.setStateAsync(`${base}.${name}`, item.value, true);\n\t\t}\n\t}\n\n\tprivate async onMessage(obj: ioBroker.Message): Promise<void> {\n\t\tif (!obj || !obj.command || !obj.callback) {\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tif (obj.command === \"searchSchools\") {\n\t\t\t\tconst results = await this.webUntis.searchSchools(this.getStringPayload(obj.message, \"query\"));\n\t\t\t\tthis.log.info(`School search returned ${results.length} results`);\n\t\t\t\tthis.sendTo(obj.from, obj.command, { ok: true, results }, obj.callback);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (obj.command === \"testConnection\") {\n\t\t\t\tconst result = await this.webUntis.testConnection(this.getConnectionPayload(obj.message));\n\t\t\t\tawait this.setState(\"info.connection\", result.ok, true);\n\t\t\t\tif (result.ok) {\n\t\t\t\t\tthis.log.info(\"WebUntis authentication successful\");\n\t\t\t\t} else {\n\t\t\t\t\tthis.log.warn(`WebUntis authentication failed: ${result.code}`);\n\t\t\t\t}\n\t\t\t\tthis.sendTo(obj.from, obj.command, result, obj.callback);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconst code = error instanceof WebUntisError ? error.code : \"UNEXPECTED_RESPONSE\";\n\t\t\tthis.log.warn(`WebUntis request failed: ${code}`);\n\t\t\tthis.sendTo(obj.from, obj.command, { ok: false, code }, obj.callback);\n\t\t}\n\t}\n\n\tprivate getStringPayload(message: ioBroker.MessagePayload, key: string): string {\n\t\tif (\n\t\t\ttypeof message !== \"object\" ||\n\t\t\tmessage === null ||\n\t\t\ttypeof (message as Record<string, unknown>)[key] !== \"string\"\n\t\t) {\n\t\t\tthrow new WebUntisError(\"INVALID_CONFIG\", \"Invalid message payload\");\n\t\t}\n\t\treturn (message as Record<string, unknown>)[key] as string;\n\t}\n\n\tprivate getConnectionPayload(message: ioBroker.MessagePayload): WebUntisConnectionConfig {\n\t\tif (typeof message !== \"object\" || message === null) {\n\t\t\tthrow new WebUntisError(\"INVALID_CONFIG\", \"Invalid connection payload\");\n\t\t}\n\t\tconst value = message as Record<string, unknown>;\n\t\tconst stringValue = (key: string): string => (typeof value[key] === \"string\" ? value[key] : \"\");\n\t\treturn {\n\t\t\tserver: stringValue(\"server\"),\n\t\t\tschoolName: stringValue(\"schoolName\"),\n\t\t\tschoolDisplayName: stringValue(\"schoolDisplayName\"),\n\t\t\tschoolAddress: stringValue(\"schoolAddress\"),\n\t\t\tschoolId: typeof value.schoolId === \"number\" ? value.schoolId : null,\n\t\t\tusername: stringValue(\"username\"),\n\t\t\tpassword: stringValue(\"password\"),\n\t\t};\n\t}\n\n\tprivate onUnload(callback: () => void): void {\n\t\tif (this.timetableTimer) {\n\t\t\tthis.clearInterval(this.timetableTimer);\n\t\t}\n\t\tif (this.currentNextTimer) {\n\t\t\tthis.clearInterval(this.currentNextTimer);\n\t\t}\n\t\tcallback();\n\t}\n}\n\nif (require.main !== module) {\n\tmodule.exports = (options: Partial<utils.AdapterOptions> | undefined) => new WebuntisNext(options);\n} else {\n\t(() => new WebuntisNext())();\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import * as utils from \"@iobroker/adapter-core\";\nimport { WebUntisService, type WebUntisConnectionConfig } from \"./lib/webuntis/WebUntisService\";\nimport { cleanupLegacyNamespace } from \"./lib/LegacyNamespaceCleanup\";\nimport type { HolidaySummary } from \"./lib/webuntis/Holidays\";\nimport { WebUntisError } from \"./lib/webuntis/WebUntisErrors\";\nimport {\n\tlessonChannelName,\n\tsummarizeTimetable,\n\tnextWeekday,\n\ttype TimetableLesson,\n\ttype TimetableSummary,\n} from \"./lib/webuntis/Timetable\";\nimport type { WebUntisHttpDiagnostic } from \"./lib/webuntis/WebUntisTypes\";\nimport { deriveCurrentNextLesson, type CurrentNextLessonSummary } from \"./lib/webuntis/CurrentNextLesson\";\n\nconst TIMETABLE_INTERVAL_MS = 5 * 60 * 1000;\nconst CURRENT_NEXT_INTERVAL_MS = 60 * 1000;\nconst TIMETABLE_GROUPS = [\"today\", \"tomorrow\", \"week\"] as const;\ntype TimetableGroup = (typeof TIMETABLE_GROUPS)[number];\n\nconst SUMMARY_STATE_DEFINITIONS: Record<\n\tkeyof TimetableSummary,\n\t{ type: \"string\" | \"number\" | \"boolean\"; role: string; name: string; def: string | number | boolean }\n> = {\n\thasSchool: { type: \"boolean\", role: \"indicator\", name: \"Has school\", def: false },\n\tlessonCount: { type: \"number\", role: \"value\", name: \"Lesson count\", def: 0 },\n\tlessonDurationMinutes: { type: \"number\", role: \"value\", name: \"Lesson duration in minutes\", def: 0 },\n\tschoolStart: { type: \"string\", role: \"text\", name: \"School start\", def: \"\" },\n\tschoolEnd: { type: \"string\", role: \"text\", name: \"School end\", def: \"\" },\n\tsubjects: { type: \"string\", role: \"text\", name: \"Subjects\", def: \"\" },\n\tsubjectCount: { type: \"number\", role: \"value\", name: \"Subject count\", def: 0 },\n\tfirstSubject: { type: \"string\", role: \"text\", name: \"First subject\", def: \"\" },\n\tlastSubject: { type: \"string\", role: \"text\", name: \"Last subject\", def: \"\" },\n\thasChanges: { type: \"boolean\", role: \"indicator\", name: \"Has changes\", def: false },\n\tchangeCount: { type: \"number\", role: \"value\", name: \"Change count\", def: 0 },\n\tcancellationCount: { type: \"number\", role: \"value\", name: \"Cancellation count\", def: 0 },\n};\n\nconst LESSON_STATE_NAMES: Record<string, string> = {\n\tdate: \"Date\",\n\tdateTimestamp: \"Date (Unix timestamp ms)\",\n\tstartTime: \"Lesson start\",\n\tendTime: \"Lesson end\",\n\tsubject: \"Subject\",\n\tsubjectLong: \"Subject name\",\n\tteacher: \"Teacher\",\n\troom: \"Room\",\n\tclass: \"Class\",\n\tlessonId: \"WebUntis lesson ID\",\n\tperiodId: \"WebUntis period ID\",\n\tstatus: \"Lesson status\",\n\tchanged: \"Lesson changed\",\n\tcancelled: \"Lesson cancelled\",\n\tsubstitution: \"Substitution\",\n\toriginalTeacher: \"Original teacher\",\n\toriginalRoom: \"Original room\",\n\toriginalSubject: \"Original subject\",\n};\n\nconst CURRENT_NEXT_STATE_DEFINITIONS: Record<\n\tkeyof CurrentNextLessonSummary,\n\t{ type: \"string\" | \"number\" | \"boolean\"; role: string; name: string; def: string | number | boolean; unit?: string }\n> = {\n\tcurrentLesson: { type: \"string\", role: \"text\", name: \"Current lesson\", def: \"\" },\n\tcurrentSubject: { type: \"string\", role: \"text\", name: \"Current subject\", def: \"\" },\n\tcurrentRoom: { type: \"string\", role: \"text\", name: \"Current room\", def: \"\" },\n\tcurrentTeacher: { type: \"string\", role: \"text\", name: \"Current teacher\", def: \"\" },\n\tnextLesson: { type: \"string\", role: \"text\", name: \"Next lesson\", def: \"\" },\n\tnextSubject: { type: \"string\", role: \"text\", name: \"Next subject\", def: \"\" },\n\tnextRoom: { type: \"string\", role: \"text\", name: \"Next room\", def: \"\" },\n\tnextTeacher: { type: \"string\", role: \"text\", name: \"Next teacher\", def: \"\" },\n\tnextLessonStart: { type: \"string\", role: \"text\", name: \"Next lesson start\", def: \"\" },\n\tminutesUntilNextLesson: {\n\t\ttype: \"number\",\n\t\trole: \"value.interval\",\n\t\tname: \"Minutes until next lesson\",\n\t\tdef: 0,\n\t\tunit: \"min\",\n\t},\n\tschoolRunning: { type: \"boolean\", role: \"indicator\", name: \"School running\", def: false },\n\tminutesUntilSchoolEnd: {\n\t\ttype: \"number\",\n\t\trole: \"value.interval\",\n\t\tname: \"Minutes until school end\",\n\t\tdef: 0,\n\t\tunit: \"min\",\n\t},\n};\n\nfunction dateOnly(value: string): string {\n\treturn value.trim().split(/[T ]/, 1)[0] || \"\";\n}\n\nfunction numericDate(value: string): number {\n\tconst [year, month, day] = dateOnly(value).split(\"-\").map(Number);\n\treturn year && month && day ? new Date(year, month - 1, day).getTime() : 0;\n}\n\nclass WebuntisNext extends utils.Adapter {\n\tprivate readonly webUntis: WebUntisService;\n\tprivate timetableTimer?: ioBroker.Interval;\n\tprivate currentNextTimer?: ioBroker.Interval;\n\tprivate todayLessons: TimetableLesson[] = [];\n\n\tpublic constructor(options: Partial<utils.AdapterOptions> = {}) {\n\t\tsuper({ ...options, name: \"webuntis2\" });\n\t\tthis.webUntis = new WebUntisService(\n\t\t\tthis.logHttpDiagnostic.bind(this),\n\t\t\tmessage => this.log.info(message),\n\t\t\tmessage => this.log.warn(message),\n\t\t\tfetch,\n\t\t\tmessage => this.log.debug(message),\n\t\t);\n\t\tthis.on(\"ready\", this.onReady.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 logHttpDiagnostic(diagnostic: WebUntisHttpDiagnostic): void {\n\t\tthis.log.debug(`WebUntis ${diagnostic.method || \"request\"} HTTP ${JSON.stringify(diagnostic)}`);\n\t}\n\n\tprivate async onReady(): Promise<void> {\n\t\tawait this.setState(\"info.connection\", false, true);\n\t\tif (!this.hasConnectionConfig()) {\n\t\t\treturn;\n\t\t}\n\t\tawait this.updateTimetable();\n\t\tthis.timetableTimer = this.setInterval(() => void this.updateTimetable(), TIMETABLE_INTERVAL_MS);\n\t\tthis.currentNextTimer = this.setInterval(() => void this.updateCurrentNextStates(), CURRENT_NEXT_INTERVAL_MS);\n\t}\n\n\tprivate hasConnectionConfig(): this is { config: WebUntisConnectionConfig } {\n\t\treturn Boolean(\n\t\t\tthis.config.server &&\n\t\t\tthis.config.schoolName &&\n\t\t\ttypeof this.config.schoolId === \"number\" &&\n\t\t\tthis.config.username &&\n\t\t\tthis.config.password,\n\t\t);\n\t}\n\n\tprivate async updateTimetable(): Promise<void> {\n\t\tawait this.setState(\"info.lastUpdate\", new Date().toISOString(), true);\n\t\ttry {\n\t\t\tawait cleanupLegacyNamespace(this, \"messages\");\n\t\t\tawait this.ensureTimetableRoot();\n\t\t\tawait this.ensureHolidaysRoot();\n\t\t\tawait this.cleanupObsoleteStructure();\n\t\t\tconst now = new Date();\n\t\t\tconst data = await this.webUntis.loadTimetable(this.config, now);\n\t\t\tthis.todayLessons = data.today;\n\t\t\tlet updated = 0;\n\t\t\tlet removed = 0;\n\t\t\tfor (const group of TIMETABLE_GROUPS) {\n\t\t\t\tconst result = await this.writeTimetableGroup(group, data[group], now);\n\t\t\t\tupdated += result.updated;\n\t\t\t\tremoved += result.removed;\n\t\t\t}\n\t\t\tif (data.holidays) {\n\t\t\t\tawait this.writeHolidaySummary(data.holidays);\n\t\t\t} else {\n\t\t\t\tthis.log.warn(\"WebUntis holidays are not available; previous holiday values were preserved\");\n\t\t\t}\n\t\t\tawait this.setState(\"info.lastSuccessfulUpdate\", now.toISOString(), true);\n\t\t\tawait this.setState(\"info.nextUpdate\", new Date(now.getTime() + TIMETABLE_INTERVAL_MS).toISOString(), true);\n\t\t\tawait this.setState(\"info.connection\", true, true);\n\t\t\tthis.log.debug(`Timetable updated: ${updated} lessons updated, ${removed} obsolete lessons removed`);\n\t\t} catch (error) {\n\t\t\tawait this.setState(\"info.connection\", false, true);\n\t\t\tawait this.setState(\"info.nextUpdate\", new Date(Date.now() + TIMETABLE_INTERVAL_MS).toISOString(), true);\n\t\t\tconst code = error instanceof WebUntisError ? error.code : \"UNEXPECTED_RESPONSE\";\n\t\t\tconst detail = error instanceof Error ? ` (${error.message})` : \"\";\n\t\t\tthis.log.warn(`Timetable update failed: ${code}${detail}; existing timetable data was kept`);\n\t\t}\n\t}\n\n\tprivate async ensureTimetableRoot(): Promise<void> {\n\t\tawait this.setObjectNotExistsAsync(\"timetable\", {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: \"Timetable\" },\n\t\t\tnative: {},\n\t\t});\n\t}\n\n\tprivate async ensureHolidaysRoot(): Promise<void> {\n\t\tawait this.setObjectNotExistsAsync(\"holidays\", {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: \"Holidays\" },\n\t\t\tnative: {},\n\t\t});\n\t\tawait this.setObjectNotExistsAsync(\"holidays.current\", {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: \"Current holiday\" },\n\t\t\tnative: {},\n\t\t});\n\t\tawait this.setObjectNotExistsAsync(\"holidays.next\", {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: \"Next holiday\" },\n\t\t\tnative: {},\n\t\t});\n\t}\n\n\tprivate async writeHolidaySummary(summary: HolidaySummary): Promise<void> {\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.current.active\",\n\t\t\tsummary.current.active,\n\t\t\t\"Active\",\n\t\t\t\"boolean\",\n\t\t\t\"indicator\",\n\t\t\tfalse,\n\t\t);\n\t\tawait this.writeSimpleState(\"holidays.current.name\", summary.current.name, \"Name\", \"string\", \"text\", \"\");\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.current.longName\",\n\t\t\tsummary.current.longName,\n\t\t\t\"Long name\",\n\t\t\t\"string\",\n\t\t\t\"text\",\n\t\t\t\"\",\n\t\t);\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.current.startDate\",\n\t\t\tdateOnly(summary.current.startDate),\n\t\t\t\"Start date\",\n\t\t\t\"string\",\n\t\t\t\"text\",\n\t\t\t\"\",\n\t\t);\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.current.startDateTimestamp\",\n\t\t\tnumericDate(summary.current.startDate),\n\t\t\t\"Start date (Unix timestamp ms)\",\n\t\t\t\"number\",\n\t\t\t\"value\",\n\t\t\t0,\n\t\t);\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.current.endDate\",\n\t\t\tdateOnly(summary.current.endDate),\n\t\t\t\"End date\",\n\t\t\t\"string\",\n\t\t\t\"text\",\n\t\t\t\"\",\n\t\t);\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.current.endDateTimestamp\",\n\t\t\tnumericDate(summary.current.endDate),\n\t\t\t\"End date (Unix timestamp ms)\",\n\t\t\t\"number\",\n\t\t\t\"value\",\n\t\t\t0,\n\t\t);\n\t\tawait this.writeSimpleState(\"holidays.next.name\", summary.next.name, \"Name\", \"string\", \"text\", \"\");\n\t\tawait this.writeSimpleState(\"holidays.next.longName\", summary.next.longName, \"Long name\", \"string\", \"text\", \"\");\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.next.startDate\",\n\t\t\tdateOnly(summary.next.startDate),\n\t\t\t\"Start date\",\n\t\t\t\"string\",\n\t\t\t\"text\",\n\t\t\t\"\",\n\t\t);\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.next.startDateTimestamp\",\n\t\t\tnumericDate(summary.next.startDate),\n\t\t\t\"Start date (Unix timestamp ms)\",\n\t\t\t\"number\",\n\t\t\t\"value\",\n\t\t\t0,\n\t\t);\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.next.endDate\",\n\t\t\tdateOnly(summary.next.endDate),\n\t\t\t\"End date\",\n\t\t\t\"string\",\n\t\t\t\"text\",\n\t\t\t\"\",\n\t\t);\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.next.daysUntil\",\n\t\t\tsummary.next.daysUntil,\n\t\t\t\"Days until\",\n\t\t\t\"number\",\n\t\t\t\"value\",\n\t\t\t0,\n\t\t);\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.next.endDateTimestamp\",\n\t\t\tnumericDate(summary.next.endDate),\n\t\t\t\"End date (Unix timestamp ms)\",\n\t\t\t\"number\",\n\t\t\t\"value\",\n\t\t\t0,\n\t\t);\n\t}\n\n\tprivate async writeDaySummary(path: string, summary: TimetableSummary): Promise<void> {\n\t\tfor (const [name, definition] of Object.entries(SUMMARY_STATE_DEFINITIONS) as [\n\t\t\tkeyof TimetableSummary,\n\t\t\t(typeof SUMMARY_STATE_DEFINITIONS)[keyof TimetableSummary],\n\t\t][]) {\n\t\t\tif (name === \"lessonCount\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tawait this.setObjectNotExistsAsync(`timetable.${path}.${name}`, {\n\t\t\t\ttype: \"state\",\n\t\t\t\tcommon: {\n\t\t\t\t\tname: definition.name,\n\t\t\t\t\ttype: definition.type,\n\t\t\t\t\trole: definition.role,\n\t\t\t\t\tread: true,\n\t\t\t\t\twrite: false,\n\t\t\t\t\tdef: definition.def,\n\t\t\t\t},\n\t\t\t\tnative: {},\n\t\t\t});\n\t\t\tawait this.extendObjectAsync(`timetable.${path}.${name}`, {\n\t\t\t\tcommon: { type: definition.type, role: definition.role, def: definition.def },\n\t\t\t});\n\t\t\tawait this.setStateAsync(`timetable.${path}.${name}`, summary[name], true);\n\t\t}\n\t}\n\n\tprivate async writeCurrentNextSummary(lessons: TimetableLesson[], now: Date): Promise<void> {\n\t\tconst summary = deriveCurrentNextLesson(lessons, now);\n\t\tfor (const [name, definition] of Object.entries(CURRENT_NEXT_STATE_DEFINITIONS) as [\n\t\t\tkeyof CurrentNextLessonSummary,\n\t\t\t(typeof CURRENT_NEXT_STATE_DEFINITIONS)[keyof CurrentNextLessonSummary],\n\t\t][]) {\n\t\t\tawait this.setObjectNotExistsAsync(`timetable.today.${name}`, {\n\t\t\t\ttype: \"state\",\n\t\t\t\tcommon: {\n\t\t\t\t\tname: definition.name,\n\t\t\t\t\ttype: definition.type,\n\t\t\t\t\trole: definition.role,\n\t\t\t\t\tread: true,\n\t\t\t\t\twrite: false,\n\t\t\t\t\tdef: definition.def,\n\t\t\t\t\t...(definition.unit ? { unit: definition.unit } : {}),\n\t\t\t\t},\n\t\t\t\tnative: {},\n\t\t\t});\n\t\t\tawait this.extendObjectAsync(`timetable.today.${name}`, {\n\t\t\t\tcommon: {\n\t\t\t\t\ttype: definition.type,\n\t\t\t\t\trole: definition.role,\n\t\t\t\t\tdef: definition.def,\n\t\t\t\t\t...(definition.unit ? { unit: definition.unit } : {}),\n\t\t\t\t},\n\t\t\t});\n\t\t\tawait this.setStateAsync(`timetable.today.${name}`, summary[name], true);\n\t\t}\n\t}\n\n\tprivate async updateCurrentNextStates(): Promise<void> {\n\t\tawait this.writeCurrentNextSummary(this.todayLessons, new Date());\n\t}\n\n\tprivate async cleanupObsoleteStructure(): Promise<void> {\n\t\tfor (const id of [\n\t\t\t\"info.timetable\",\n\t\t\t\"timetable.timetable\",\n\t\t\t\"timetable.today.count\",\n\t\t\t\"timetable.tomorrow.count\",\n\t\t\t\"timetable.today.subjectsJson\",\n\t\t\t\"timetable.tomorrow.subjectsJson\",\n\t\t]) {\n\t\t\tif (await this.getObjectAsync(id)) {\n\t\t\t\tawait this.delObjectAsync(id, { recursive: true });\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async writeTimetableGroup(\n\t\tgroup: TimetableGroup,\n\t\tlessons: TimetableLesson[],\n\t\tnow: Date,\n\t): Promise<{ updated: number; removed: number }> {\n\t\tawait this.setObjectNotExistsAsync(`timetable.${group}`, {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: `Timetable ${group}` },\n\t\t\tnative: {},\n\t\t});\n\t\tlet removed = await this.removeLegacyLessons(group);\n\t\tif (group === \"week\") {\n\t\t\tconst weekdayNames = [\"monday\", \"tuesday\", \"wednesday\", \"thursday\", \"friday\", \"saturday\", \"sunday\"];\n\t\t\tconst byDay = weekdayNames.map((_, index) => {\n\t\t\t\tconst targetDate = this.timetableDate(nextWeekday(now, index));\n\t\t\t\treturn lessons.filter(lesson => lesson.date === targetDate);\n\t\t\t});\n\t\t\tfor (let index = 0; index < weekdayNames.length; index++) {\n\t\t\t\tconst result = await this.writeTimetableDay(\n\t\t\t\t\t`timetable.week.${weekdayNames[index]}`,\n\t\t\t\t\tbyDay[index],\n\t\t\t\t\tthis.timetableDate(nextWeekday(now, index)),\n\t\t\t\t);\n\t\t\t\tawait this.writeDaySummary(`week.${weekdayNames[index]}`, summarizeTimetable(byDay[index]));\n\t\t\t\tremoved += result.removed;\n\t\t\t}\n\t\t} else {\n\t\t\tconst day = new Date(now);\n\t\t\tif (group === \"tomorrow\") {\n\t\t\t\tday.setDate(day.getDate() + 1);\n\t\t\t}\n\t\t\tconst result = await this.writeTimetableDay(`timetable.${group}`, lessons, this.timetableDate(day));\n\t\t\tawait this.writeDaySummary(group, summarizeTimetable(lessons));\n\t\t\tif (group === \"today\") {\n\t\t\t\tawait this.writeCurrentNextSummary(lessons, now);\n\t\t\t}\n\t\t\tremoved += result.removed;\n\t\t}\n\t\treturn { updated: lessons.length, removed };\n\t}\n\n\tprivate async removeLegacyLessons(group: TimetableGroup): Promise<number> {\n\t\tconst existing = await this.getObjectListAsync({\n\t\t\tstartkey: `${this.namespace}.timetable.${group}.`,\n\t\t\tendkey: `${this.namespace}.timetable.${group}.\\uffff`,\n\t\t});\n\t\tconst legacy = new Set<string>();\n\t\tfor (const object of existing.rows || []) {\n\t\t\tconst first = object.id.replace(`${this.namespace}.timetable.${group}.`, \"\").split(\".\")[0];\n\t\t\tif (first.startsWith(\"period-\")) {\n\t\t\t\tlegacy.add(first);\n\t\t\t}\n\t\t}\n\t\tfor (const id of legacy) {\n\t\t\tawait this.delObjectAsync(`timetable.${group}.${id}`, { recursive: true });\n\t\t}\n\t\treturn legacy.size;\n\t}\n\n\tprivate async writeTimetableDay(\n\t\tpath: string,\n\t\tlessons: TimetableLesson[],\n\t\tdate: string,\n\t): Promise<{ removed: number }> {\n\t\tawait this.setObjectNotExistsAsync(path, {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: path.split(\".\").at(-1) || \"Day\" },\n\t\t\tnative: {},\n\t\t});\n\t\tawait this.writeSimpleState(`${path}.date`, dateOnly(date), \"Date\", \"string\", \"text\", \"\");\n\t\tawait this.writeSimpleState(\n\t\t\t`${path}.dateTimestamp`,\n\t\t\tnumericDate(date),\n\t\t\t\"Date (Unix timestamp ms)\",\n\t\t\t\"number\",\n\t\t\t\"value\",\n\t\t\t0,\n\t\t);\n\t\tawait this.writeSimpleState(`${path}.lessonCount`, lessons.length, \"Lesson count\", \"number\", \"value\", 0);\n\t\tawait this.setObjectNotExistsAsync(`${path}.lessons`, {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: \"Lessons\" },\n\t\t\tnative: {},\n\t\t});\n\t\tconst expected = new Set(lessons.map((_lesson, index) => String(index + 1).padStart(2, \"0\")));\n\t\tconst existing = await this.getObjectListAsync({\n\t\t\tstartkey: `${this.namespace}.${path}.lessons.`,\n\t\t\tendkey: `${this.namespace}.${path}.lessons.\\uffff`,\n\t\t});\n\t\tconst stale = new Set<string>();\n\t\tfor (const object of existing.rows || []) {\n\t\t\tconst slot = object.id.replace(`${this.namespace}.${path}.lessons.`, \"\").split(\".\")[0];\n\t\t\tif (slot && !expected.has(slot)) {\n\t\t\t\tstale.add(slot);\n\t\t\t}\n\t\t}\n\t\tfor (const slot of stale) {\n\t\t\tawait this.delObjectAsync(`${path}.lessons.${slot}`, { recursive: true });\n\t\t}\n\t\tfor (const [index, lesson] of lessons.entries()) {\n\t\t\tawait this.writeLesson(path, String(index + 1).padStart(2, \"0\"), lesson);\n\t\t}\n\t\treturn { removed: stale.size };\n\t}\n\n\tprivate timetableDate(date: Date): string {\n\t\treturn `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, \"0\")}-${String(date.getDate()).padStart(2, \"0\")}`;\n\t}\n\n\tprivate async writeSimpleState(\n\t\tid: string,\n\t\tvalue: string | number | boolean,\n\t\tname: string,\n\t\ttype: \"string\" | \"number\" | \"boolean\",\n\t\trole: string,\n\t\tdef: string | number | boolean,\n\t): Promise<void> {\n\t\tawait this.setObjectNotExistsAsync(id, {\n\t\t\ttype: \"state\",\n\t\t\tcommon: { name, type, role, read: true, write: false, def },\n\t\t\tnative: {},\n\t\t});\n\t\tawait this.extendObjectAsync(id, { common: { name, type, role, read: true, write: false, def } });\n\t\tawait this.setStateAsync(id, value, true);\n\t}\n\n\tprivate async writeLesson(path: string, slot: string, lesson: TimetableLesson): Promise<void> {\n\t\tconst base = `${path}.lessons.${slot}`;\n\t\tconst label = lessonChannelName(lesson);\n\t\tawait this.setObjectNotExistsAsync(base, {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: label || `Lesson ${slot}` },\n\t\t\tnative: {},\n\t\t});\n\t\tawait this.extendObjectAsync(base, { common: { name: label || `Lesson ${slot}` } });\n\t\tconst values: Record<\n\t\t\tstring,\n\t\t\t{ value: string | number | boolean; type: \"string\" | \"number\" | \"boolean\"; role: string }\n\t\t> = {\n\t\t\tdate: { value: dateOnly(lesson.date), type: \"string\", role: \"text\" },\n\t\t\tdateTimestamp: { value: numericDate(lesson.date), type: \"number\", role: \"value\" },\n\t\t\tstartTime: { value: lesson.startTime, type: \"string\", role: \"text\" },\n\t\t\tendTime: { value: lesson.endTime, type: \"string\", role: \"text\" },\n\t\t\tsubject: { value: lesson.subject, type: \"string\", role: \"text\" },\n\t\t\tsubjectLong: { value: lesson.subjectLong, type: \"string\", role: \"text\" },\n\t\t\tteacher: { value: lesson.teacher, type: \"string\", role: \"text\" },\n\t\t\troom: { value: lesson.room, type: \"string\", role: \"text\" },\n\t\t\tclass: { value: lesson.class, type: \"string\", role: \"text\" },\n\t\t\t...(lesson.lessonId === null\n\t\t\t\t? {}\n\t\t\t\t: { lessonId: { value: String(lesson.lessonId), type: \"string\" as const, role: \"text\" } }),\n\t\t\t...(lesson.periodId === null\n\t\t\t\t? {}\n\t\t\t\t: { periodId: { value: String(lesson.periodId), type: \"string\" as const, role: \"text\" } }),\n\t\t\tstatus: { value: lesson.status, type: \"string\", role: \"text\" },\n\t\t\tchanged: { value: lesson.changed, type: \"boolean\", role: \"indicator\" },\n\t\t\tcancelled: { value: lesson.cancelled, type: \"boolean\", role: \"indicator\" },\n\t\t\t...(lesson.substitution\n\t\t\t\t? { substitution: { value: lesson.substitution, type: \"string\" as const, role: \"text\" } }\n\t\t\t\t: {}),\n\t\t\t...(lesson.originalTeacher && lesson.originalTeacher !== lesson.teacher\n\t\t\t\t? { originalTeacher: { value: lesson.originalTeacher, type: \"string\" as const, role: \"text\" } }\n\t\t\t\t: {}),\n\t\t\t...(lesson.originalRoom && lesson.originalRoom !== lesson.room\n\t\t\t\t? { originalRoom: { value: lesson.originalRoom, type: \"string\" as const, role: \"text\" } }\n\t\t\t\t: {}),\n\t\t\t...(lesson.originalSubject && lesson.originalSubject !== lesson.subject\n\t\t\t\t? { originalSubject: { value: lesson.originalSubject, type: \"string\" as const, role: \"text\" } }\n\t\t\t\t: {}),\n\t\t};\n\t\tconst optional = [\"substitution\", \"originalTeacher\", \"originalRoom\", \"originalSubject\"];\n\t\tfor (const name of optional) {\n\t\t\tif (!(name in values) && (await this.getObjectAsync(`${base}.${name}`))) {\n\t\t\t\tawait this.delObjectAsync(`${base}.${name}`);\n\t\t\t}\n\t\t}\n\t\tfor (const [name, item] of Object.entries(values)) {\n\t\t\tawait this.setObjectNotExistsAsync(`${base}.${name}`, {\n\t\t\t\ttype: \"state\",\n\t\t\t\tcommon: {\n\t\t\t\t\tname: LESSON_STATE_NAMES[name] || name,\n\t\t\t\t\ttype: item.type,\n\t\t\t\t\trole: item.role,\n\t\t\t\t\tread: true,\n\t\t\t\t\twrite: false,\n\t\t\t\t\tdef: item.value,\n\t\t\t\t},\n\t\t\t\tnative: {},\n\t\t\t});\n\t\t\tawait this.extendObjectAsync(`${base}.${name}`, {\n\t\t\t\tcommon: { name: LESSON_STATE_NAMES[name] || name, type: item.type, role: item.role, def: item.value },\n\t\t\t});\n\t\t\tawait this.setStateAsync(`${base}.${name}`, item.value, true);\n\t\t}\n\t}\n\n\tprivate async onMessage(obj: ioBroker.Message): Promise<void> {\n\t\tif (!obj || !obj.command || !obj.callback) {\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tif (obj.command === \"searchSchools\") {\n\t\t\t\tconst results = await this.webUntis.searchSchools(this.getStringPayload(obj.message, \"query\"));\n\t\t\t\tthis.log.info(`School search returned ${results.length} results`);\n\t\t\t\tthis.sendTo(obj.from, obj.command, { ok: true, results }, obj.callback);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (obj.command === \"testConnection\") {\n\t\t\t\tconst result = await this.webUntis.testConnection(this.getConnectionPayload(obj.message));\n\t\t\t\tawait this.setState(\"info.connection\", result.ok, true);\n\t\t\t\tif (result.ok) {\n\t\t\t\t\tthis.log.info(\"WebUntis authentication successful\");\n\t\t\t\t} else {\n\t\t\t\t\tthis.log.warn(`WebUntis authentication failed: ${result.code}`);\n\t\t\t\t}\n\t\t\t\tthis.sendTo(obj.from, obj.command, result, obj.callback);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconst code = error instanceof WebUntisError ? error.code : \"UNEXPECTED_RESPONSE\";\n\t\t\tthis.log.warn(`WebUntis request failed: ${code}`);\n\t\t\tthis.sendTo(obj.from, obj.command, { ok: false, code }, obj.callback);\n\t\t}\n\t}\n\n\tprivate getStringPayload(message: ioBroker.MessagePayload, key: string): string {\n\t\tif (\n\t\t\ttypeof message !== \"object\" ||\n\t\t\tmessage === null ||\n\t\t\ttypeof (message as Record<string, unknown>)[key] !== \"string\"\n\t\t) {\n\t\t\tthrow new WebUntisError(\"INVALID_CONFIG\", \"Invalid message payload\");\n\t\t}\n\t\treturn (message as Record<string, unknown>)[key] as string;\n\t}\n\n\tprivate getConnectionPayload(message: ioBroker.MessagePayload): WebUntisConnectionConfig {\n\t\tif (typeof message !== \"object\" || message === null) {\n\t\t\tthrow new WebUntisError(\"INVALID_CONFIG\", \"Invalid connection payload\");\n\t\t}\n\t\tconst value = message as Record<string, unknown>;\n\t\tconst stringValue = (key: string): string => (typeof value[key] === \"string\" ? value[key] : \"\");\n\t\treturn {\n\t\t\tserver: stringValue(\"server\"),\n\t\t\tschoolName: stringValue(\"schoolName\"),\n\t\t\tschoolDisplayName: stringValue(\"schoolDisplayName\"),\n\t\t\tschoolAddress: stringValue(\"schoolAddress\"),\n\t\t\tschoolId: typeof value.schoolId === \"number\" ? value.schoolId : null,\n\t\t\tusername: stringValue(\"username\"),\n\t\t\tpassword: stringValue(\"password\"),\n\t\t};\n\t}\n\n\tprivate onUnload(callback: () => void): void {\n\t\tif (this.timetableTimer) {\n\t\t\tthis.clearInterval(this.timetableTimer);\n\t\t}\n\t\tif (this.currentNextTimer) {\n\t\t\tthis.clearInterval(this.currentNextTimer);\n\t\t}\n\t\tcallback();\n\t}\n}\n\nif (require.main !== module) {\n\tmodule.exports = (options: Partial<utils.AdapterOptions> | undefined) => new WebuntisNext(options);\n} else {\n\t(() => new WebuntisNext())();\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "webuntis2",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.1",
|
|
5
5
|
"news": {
|
|
6
|
+
"0.1.1": {
|
|
7
|
+
"en": "Improved rolling weekly timetable, weekly summaries and date states with Unix timestamps",
|
|
8
|
+
"de": "Verbesserte rollierende Wochenansicht, Wochentagszusammenfassungen und Datumsdatenpunkte mit Unix-Zeitstempeln",
|
|
9
|
+
"ru": "Улучшенное скользящее недельное расписание, сводки по дням недели и состояния дат с временными метками Unix",
|
|
10
|
+
"pt": "Calendário semanal contínuo melhorado, resumos dos dias da semana e estados de data com marcas de tempo Unix",
|
|
11
|
+
"nl": "Verbeterd doorlopend weekrooster, weeksamenvattingen en datumstatussen met Unix-tijdstempels",
|
|
12
|
+
"fr": "Planning hebdomadaire glissant amélioré, résumés des jours de la semaine et états de date avec horodatages Unix",
|
|
13
|
+
"it": "Calendario settimanale continuo migliorato, riepiloghi dei giorni della settimana e stati delle date con timestamp Unix",
|
|
14
|
+
"es": "Calendario semanal continuo mejorado, resúmenes de los días de la semana y estados de fecha con marcas de tiempo Unix",
|
|
15
|
+
"pl": "Ulepszony kroczący tygodniowy plan lekcji, podsumowania dni tygodnia i stany dat z sygnaturami czasu Unix",
|
|
16
|
+
"uk": "Покращений ковзний тижневий розклад, підсумки днів тижня та стани дат із часовими мітками Unix",
|
|
17
|
+
"zh-cn": "改进的滚动周课表、每周每日摘要以及带 Unix 时间戳的日期状态"
|
|
18
|
+
},
|
|
6
19
|
"0.1.0": {
|
|
7
20
|
"en": "complete feature release",
|
|
8
21
|
"de": "vollständige Funktionsveröffentlichung",
|
|
@@ -95,7 +108,7 @@
|
|
|
95
108
|
],
|
|
96
109
|
"globalDependencies": [
|
|
97
110
|
{
|
|
98
|
-
"admin": ">=7.
|
|
111
|
+
"admin": ">=7.8.23"
|
|
99
112
|
}
|
|
100
113
|
]
|
|
101
114
|
},
|