diff --git a/app/lib/constants.ts b/app/lib/constants.ts index c3ba4dd..0d5682d 100644 --- a/app/lib/constants.ts +++ b/app/lib/constants.ts @@ -1,10 +1,10 @@ -export const VERSION = '1.6.2' +export const VERSION = '1.7.0' export const RequiredVersions = { controller: VERSION, tts: '2.0.0', piper: '1.3.0', - sounder: '2.1.0', + sounder: '2.4.0', button: '1.0.0' } diff --git a/app/lib/settings.server.ts b/app/lib/settings.server.ts index e8af140..d8ecdb4 100644 --- a/app/lib/settings.server.ts +++ b/app/lib/settings.server.ts @@ -2,34 +2,30 @@ import {asyncForEach} from '@arcath/utils' import {getPrisma} from './prisma.server' type SettingKey = - | 'lockdownEntrySound' - | 'lockdownExitSound' | 'lockdownRepeat' - | 'lockdownExitRepeat' | 'lockdownMode' | 'lockdownRepeatRingerWire' - | 'lockdownRepetitions' | 'password' | 'ttsSpeed' | 'enrollUrl' | 'controlPointKey' | 'ttsLastSeen' | 'workerLastSeen' + | 'lockdownEntrySequence' + | 'lockdownExitSequence' export const DEFAULT_SETTINGS: {[setting in SettingKey]: string} = { - lockdownEntrySound: '', - lockdownExitSound: '', lockdownRepeat: '5', - lockdownExitRepeat: '2', lockdownRepeatRingerWire: '0', lockdownMode: '0', - lockdownRepetitions: '4', password: 'bell', ttsSpeed: '1', enrollUrl: 'http://controller:3000', controlPointKey: '', ttsLastSeen: '"1970-01-01T23:00:00.000Z"', - workerLastSeen: '"1970-01-01T23:00:00.000Z"' + workerLastSeen: '"1970-01-01T23:00:00.000Z"', + lockdownEntrySequence: '[]', + lockdownExitSequence: '[]' } export const getSetting = async (setting: SettingKey) => { diff --git a/app/locales/en.ts b/app/locales/en.ts index b94aace..7e1b01f 100644 --- a/app/locales/en.ts +++ b/app/locales/en.ts @@ -193,6 +193,12 @@ export const en = { 'lockdown.field.entrySound.label': 'Lockdown start sound', 'lockdown.field.entrySound.helper': 'Sound used to start lockdown and for repetitions.', + 'lockdown.field.entrySequence.label': 'Lockdown Entry Sequence', + 'lockdown.field.entrySequence.helper': + 'The sequence that is run when lockdown starts and on any repetitions.', + 'lockdown.field.exitSequence.label': 'Lockdown Exit Sequence', + 'lockdown.field.exitSequence.helper': + 'The sequence that is run when lockdown ends.', 'lockdown.field.exitSound.label': 'Lockdown end sound', 'lockdown.field.exitSound.helper': 'Sound used to end lockdown.', 'lockdown.field.startCount.label': 'Lockdown start count', diff --git a/app/root.tsx b/app/root.tsx index 85d23d9..95b40cc 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -146,7 +146,7 @@ const AppContent = () => {
- © Open School Bell 2025
+ © Open School Bell 2026
OSB {VERSION}
diff --git a/app/routes/lockdown.tsx b/app/routes/lockdown.tsx index 769a989..2aa4492 100644 --- a/app/routes/lockdown.tsx +++ b/app/routes/lockdown.tsx @@ -15,6 +15,7 @@ import {Page, FormElement, Actions} from '~/lib/ui' import {useTranslation} from '~/lib/i18n' import {translate} from '~/lib/i18n.shared' import {getRootI18n} from '~/lib/i18n.meta' +import {SequenceBuilder} from '~/lib/sequence-builder' export const meta: MetaFunction = ({matches}) => { const {messages} = getRootI18n(matches) @@ -31,19 +32,15 @@ export const loader = async ({request}: LoaderFunctionArgs) => { const { lockdownMode, lockdownRepeat, - lockdownExitRepeat, - lockdownEntrySound, - lockdownExitSound, lockdownRepeatRingerWire, - lockdownRepetitions + lockdownEntrySequence, + lockdownExitSequence } = await getSettings([ - 'lockdownEntrySound', 'lockdownMode', 'lockdownRepeat', - 'lockdownExitRepeat', - 'lockdownExitSound', 'lockdownRepeatRingerWire', - 'lockdownRepetitions' + 'lockdownEntrySequence', + 'lockdownExitSequence' ]) const prisma = getPrisma() @@ -53,11 +50,9 @@ export const loader = async ({request}: LoaderFunctionArgs) => { return { lockdownMode, lockdownRepeat, - lockdownExitRepeat, - lockdownEntrySound, - lockdownExitSound, lockdownRepeatRingerWire, - lockdownRepetitions, + lockdownEntrySequence, + lockdownExitSequence, sounds } } @@ -65,37 +60,27 @@ export const loader = async ({request}: LoaderFunctionArgs) => { export const action = async ({request}: ActionFunctionArgs) => { const formData = await request.formData() - const lockdownEntrySound = formData.get('lockdownEntrySound') as - | string - | undefined - const lockdownExitSound = formData.get('lockdownExitSound') as - | string - | undefined - const lockdownRepetitions = formData.get('lockdownRepetitions') as + const lockdownRepeat = formData.get('lockdownRepeat') as string | undefined + const lockdownEntrySequence = formData.get('lockdownEntrySequence') as | string | undefined - const lockdownExitRepeat = formData.get('lockdownExitRepeat') as + const lockdownExitSequence = formData.get('lockdownExitSequence') as | string | undefined - const lockdownRepeat = formData.get('lockdownRepeat') as string | undefined const lockdownRepeatRingerWire = !!(formData.get( 'lockdownRepeatRingerWire' ) as string | undefined) ? '1' : '0' - invariant(lockdownEntrySound) - invariant(lockdownExitSound) - invariant(lockdownRepetitions) invariant(lockdownRepeat) - invariant(lockdownExitRepeat) + invariant(lockdownEntrySequence) + invariant(lockdownExitSequence) - await setSetting('lockdownEntrySound', lockdownEntrySound) - await setSetting('lockdownExitSound', lockdownExitSound) - await setSetting('lockdownRepetitions', lockdownRepetitions) - await setSetting('lockdownExitRepeat', lockdownExitRepeat) await setSetting('lockdownRepeat', lockdownRepeat) await setSetting('lockdownRepeatRingerWire', lockdownRepeatRingerWire) + await setSetting('lockdownEntrySequence', lockdownEntrySequence) + await setSetting('lockdownExitSequence', lockdownExitSequence) return redirect('/lockdown') } @@ -104,11 +89,9 @@ const Lockdown = () => { const { lockdownMode, lockdownRepeat, - lockdownExitRepeat, - lockdownEntrySound, - lockdownExitSound, lockdownRepeatRingerWire, - lockdownRepetitions, + lockdownEntrySequence, + lockdownExitSequence, sounds } = useLoaderData() const {t} = useTranslation() @@ -123,64 +106,20 @@ const Lockdown = () => { : t('lockdown.status.inactive')}{' '}
- - - - - - - - - - - - + + { const { lockdownMode, lockdownRepeat, - lockdownExitRepeat, - lockdownEntrySound, - lockdownExitSound, - lockdownRepeatRingerWire, - lockdownRepetitions + lockdownEntrySequence, + lockdownExitSequence, + lockdownRepeatRingerWire } = await getSettings([ - 'lockdownEntrySound', + 'lockdownEntrySequence', + 'lockdownExitSequence', 'lockdownMode', 'lockdownRepeat', - 'lockdownExitSound', - 'lockdownRepeatRingerWire', - 'lockdownRepetitions', - 'lockdownExitRepeat' + 'lockdownRepeatRingerWire' ]) - const entrySound = await prisma.audio.findFirstOrThrow({ - where: {id: lockdownEntrySound} - }) - const exitSound = await prisma.audio.findFirstOrThrow({ - where: {id: lockdownExitSound} - }) - return Response.json({ id: sounder.id, name: sounder.name, @@ -70,10 +59,8 @@ export const action = async ({request}: ActionFunctionArgs) => { ), lockdown: { enable: lockdownMode === '1', - entrySound: entrySound.id, - exitSound: exitSound.id, - times: parseInt(lockdownRepetitions), - exitTimes: parseInt(lockdownExitRepeat), + entrySequence: lockdownEntrySequence, + exitSequence: lockdownExitSequence, interval: parseInt(lockdownRepeat), repeatRingerWire: lockdownRepeatRingerWire === '1' } diff --git a/prisma/seed.js b/prisma/seed.js index d20836d..690ed04 100644 --- a/prisma/seed.js +++ b/prisma/seed.js @@ -87,6 +87,91 @@ const main = async () => { }) }) ) + + const lockdownSettings = await prisma.setting.findMany({ + where: { + key: { + in: [ + 'lockdownEntrySound', + 'lockdownExitSound', + 'lockdownExitRepeat', + 'lockdownRepetitions' + ] + } + } + }) + + if (lockdownSettings.length > 0) { + const lockdownEntrySound = lockdownSettings.reduce((v, {key, value}) => { + if (v) return v + if (key === 'lockdownEntrySound') return value + return undefined + }, undefined) + + const lockdownRepetitions = lockdownSettings.reduce((v, {key, value}) => { + if (v) return v + if (key === 'lockdownRepetitions') return value + return undefined + }, undefined) + + if (lockdownEntrySound && lockdownRepetitions) { + const entrySequence = [] + + let i = 0 + while (i < parseInt(lockdownRepetitions)) { + entrySequence.push(lockdownEntrySound) + i++ + } + + await prisma.setting.upsert({ + where: {key: 'lockdownEntrySequence'}, + create: { + key: 'lockdownEntrySequence', + value: JSON.stringify(entrySequence) + }, + update: {value: JSON.stringify(entrySequence)} + }) + + await prisma.setting.deleteMany({ + where: {key: {in: ['lockdownEntrySound', 'lockdownRepetitions']}} + }) + } + + const lockdownExitSound = lockdownSettings.reduce((v, {key, value}) => { + if (v) return v + if (key === 'lockdownExitSound') return value + return undefined + }, undefined) + + const lockdownExitRepeat = lockdownSettings.reduce((v, {key, value}) => { + if (v) return v + if (key === 'lockdownExitRepeat') return value + return undefined + }, undefined) + + if (lockdownExitSound && lockdownExitRepeat) { + const exitSequence = [] + + let i = 0 + while (i < parseInt(lockdownExitRepeat)) { + exitSequence.push(lockdownExitSound) + i++ + } + + await prisma.setting.upsert({ + where: {key: 'lockdownExitSequence'}, + create: { + key: 'lockdownExitSequence', + value: JSON.stringify(exitSequence) + }, + update: {value: JSON.stringify(exitSequence)} + }) + + await prisma.setting.deleteMany({ + where: {key: {in: ['lockdownExitSound', 'lockdownExitRepeat']}} + }) + } + } } main()