Introduction
Multilarm is a cross-platform console application for Windows and Linux that combines a precision audio scheduler, a virtual radio station and a speech-segment player into one fully offline, headless-capable tool. At its core it fires audio files at precise times — every day, specific weekdays, monthly by day-number, or against a full yearly calendar — making it the ideal engine for a virtual Muezzin, automated PA system, school bell, or any environment where reliable timed audio is required without an internet connection.
Beyond fixed alarms, Multilarm continuously fills silence between events with a virtual radio drawn from a local audio library. Its subfolder-aware shuffle cycles through folders in a randomised order, interleaving tracks so no file repeats until the whole library has played. Playback windows are defined by flexible schedule rules covering time ranges, weekdays, Nth-weekday-of-month, date ranges, and midnight-crossing spans — all combinable with inclusion and exclusion filters. On top of that, a QuotePlayer module fires random speech segments from a long audio file at configurable intervals, using RMS amplitude analysis to locate natural silence boundaries and produce clean, varied excerpts.
Each alarm event can display a customisable console message and speak it aloud using a pre-recorded word library (built with the built-in Ctrl+R recording interface). Dynamic tokens such as #ALARM+1# and #TIMETOALARM+1# insert the next alarm time and countdown into the message automatically. An ambient sound layer plays random-duration clips from a separate file at a fixed interval, keeping environments pleasantly filled between all other audio activity.
Equipment and electricity overhead can be minimised by deploying Multilarm in headless mode on a small single-board computer such as a Raspberry Pi, pairing it with an appropriate audio HAT and speaker. A one-command install script handles driver setup automatically on Linux ARM systems, and a systemd service can be configured to start Multilarm at boot with no further interaction.
What a site actually costs. The licence is perpetual — bought once, no expiry and no phone-home check — so most of a multi-year figure is spent in year one. Prices are listed on the pricing page, and the five-year cost calculator adds a real site up over three, five or ten years: licence, hardware if you are buying it, commissioning if you want an installer, optional Cloud Relay and optional annual maintenance. It leaves out speakers, amplifiers and cabling, which are a building’s cost rather than ours, and it puts no pound value on staff time saved.
Features
Precision Audio Scheduling
Trigger any audio file at exact times — daily, on named weekdays, by day-of-month, or from a full yearly timetable. Multiple audio folders map to individual time slots via an index, so different sounds fire at different events from the same schedule. UK BST/GMT daylight saving is applied automatically.
Virtual Radio
Continuous background playback from either a local audio library or an internet Shoutcast/Icecast stream during configurable time windows. Subfolder-aware shuffle interleaves local tracks across folders in a no-repeat cycle. Internet streams automatically fall back to the local library on connection failure and reconnect on a timer. Schedule rules support weekdays, Nth-weekday-of-month, date and month ranges, midnight-crossing spans, and exclusion filters — all combinable per rule.
Music Library
Indexes one or more audio folders and reads what is already in your files — title, artist, album, genre, year and BPM from ID3v1, ID3v2, FLAC, Ogg, MP4 and WAV tags — alongside duration, sample rate, channels and bitrate. WAV files are additionally measured for peak and RMS level, crest factor, clipping and leading/trailing silence, so the one track that is twice as loud as the rest is found before a room finds it. Your files are never modified: corrections to a title, cue point, gain or track type are stored as overrides in the index, so a library another program also manages cannot be damaged, and any track can be reset back to its own tags. Scanning is incremental, cancellable, and only removes missing entries after a complete pass. Four built-in reports cover what is unreadable, what is missing metadata, what is clipped and what is duplicated. Embedded cover art is located rather than extracted — the scan records where the picture sits in the file (ID3v2 APIC, FLAC picture blocks, MP4 covr) and the dashboard reads it on demand, so a large scan is not spent decoding images and there is no thumbnail cache to go stale when you re-tag.
Static & Smart Playlists
A static playlist is a running order; a smart playlist is a set of rules resolved live — genre, artist, album, title, comment, track type, path, year, BPM, duration, play count and days since last played, combined with is / is not / contains / does not contain / starts with / greater than / less than / between, matched all-or-any, optionally limited and sorted. Playlists nest up to six deep, and a save that would make a playlist contain itself is refused rather than accepted and then looped over — and a refused save changes nothing, leaving the playlist exactly as it was. A rule naming a field or an operator that does not exist is refused too, with the valid ones listed, rather than quietly rewritten into a rule that matches something else. A smart playlist can be frozen, pinning today’s resolution so an event that must be identical every rehearsal cannot change under the people rehearsing it.
Rotation Engine with Dead-Air Guard
Chooses the next track across several playlists by weight, honouring separation rules — no same track within N minutes, no same artist within N minutes, no same album within N tracks, no repeat within N tracks — and firing interrupting playlists every N tracks or every N minutes inside an optional clock window, for the jingle, the ident or the hourly reminder. If the rules leave nothing to play, the engine relaxes them in a fixed order rather than going quiet (album window, then artist window, then track window, then all repeat rules, least-recently-played first) and logs every relaxation. Under all of it sits an optional safety folder, read directly without the library index, for the case where the index is gone or the music share did not mount. Silence on a PA is a fault; a repeated artist is not.
Music Slots (Dayparting)
Between these clock times, on these days, the rotation draws from these playlists — then hands back to the ordinary rotation. Slots may wrap midnight; on an overlap the higher priority wins and a tie goes to the narrower window. Each slot can open and close with its own ident playlist (one-shot, never retried into a loop), resolve its content a set number of seconds before air so the first track starts on time rather than after a cold query, and share one running order with every other slot carrying the same link key, so “the 09:00 hour, repeated at 15:00” genuinely repeats. Overrun is a per-slot switch: off, the slot will not start a track that cannot finish in time; if nothing is short enough it starts one anyway, because a daypart boundary never outranks the dead-air guard. Nothing in it plays, stops or sets a volume — a misconfigured slot yields the ordinary rotation, not quiet.
Now Playing & Play Log
One announcement point feeds the play log, the outbound webhooks, the operator dashboard and a self-contained public /onair page, so no two surfaces can disagree about what is on air. The public feed carries track metadata only — never a file path, folder or machine name. Everything that goes out is written to a monthly CSV, exportable as plain columns or in the shape PRS, PPL and SoundExchange returns ask for, with announcements excluded from the music totals and unknown fields (ISRC, label, service name) left blank rather than invented. It produces the paperwork; it offers no view on whether a licence is needed, which one, or what it costs.
Podcast Ingest & Publishing
Subscribe to an RSS feed and new episodes are downloaded and indexed automatically, so a daily bulletin or weekly talk drops into a playlist without anybody copying files. Every URL must be http(s), every download is size-capped and extension-checked, filenames are derived from the episode title rather than anything in the URL, and a partial download is never renamed into place. Nothing downloaded plays by itself. In the other direction, scheduled recordings are offered at /podcast.xml as an RSS 2.0 feed with iTunes tags — and the generator parses its own output before serving it, refusing to publish a document that does not load.
LAN Listen Endpoint
An optional endpoint so somebody on the same network can hear what the PA is playing in a browser with nothing to install: 16-bit PCM in an open-ended WAV stream, up to 32 listeners, Icecast-shaped headers so ordinary players accept it, and a listen key checked in constant time. Three mounts come off one read of the master tap — the full mix, a mono one at half the bandwidth and a low-bandwidth one at a quarter — and a mount nobody is listening to is never encoded. Stated plainly: this is not an Icecast source and not internet streaming. At roughly 1.5 Mbit/s per listener on the full mount — 1.54 measured on the reference Pi at 48 kHz — it is LAN quality at LAN scale. It refuses to bind the network without a listen key, and refuses to start at all while multi-room sync is running, because both need the engine’s single master tap.
Silence Fallback for Listeners
Point the listen endpoint at a short WAV and a gap in the programme carries that on a loop instead of digital silence, so a quiet period sounds like a hold loop rather than a dead line. It is heard by listeners only — the building itself stays quiet, which is the whole point of a hold loop on a PA. The file must be 16-bit WAV under a minute and match the engine’s sample rate and channel count exactly; anything else is refused with a note in the status rather than quietly resampled into something that sounds wrong. The status reports the engine’s own rate and channel count whether the endpoint is running or not, so the two numbers you need are there before you build the file. Every gap restarts the loop from the top rather than resuming mid-word.
Listener Analytics
Connections, peak, listening time and a “unique today” figure, bucketed by hour and by day with the last fifty sessions listed. Counts, not identities: no address is ever written to disk, nothing is sent off the device, and the play log is deliberately not joined to it. The unique figure uses a salted fingerprint held in memory for the current day only — enough to stop one listener counting five times, and not built to identify anybody. A session is credited to the hour it started in, so a long listen is not smeared across the chart.
Embeddable Player & Schedule
A standalone player page and a weekly schedule grid, both sized to drop straight into an iframe on a site of your own, with an optional stylesheet so an embed can match the page around it. The schedule is derived from the music slots that actually drive the rotation, so it cannot drift from what plays. Neither page can start, stop or set a volume.
Listen Again
Finished scheduled recordings and library tracks played back in a browser, served from where the files already sit — nothing copied, transcoded or cached. Seeking works, so somebody can jump to the part of an assembly they wanted instead of sitting through it. A requested recording is matched against the folder listing rather than joined onto a path, so a caller cannot walk out of the folder.
QuotePlayer
Plays a clean, randomly positioned excerpt from a long spoken-word file at a set interval. RMS amplitude analysis locates natural silence boundaries on both sides of a randomly chosen position, so every playback starts and ends in a true gap — no mid-word cuts.
Ambient Sound
A separate ambient layer plays random-duration clips from a background audio file at a fixed interval, running independently of alarms, radio and quotes to keep environments continuously filled.
Timed Console Messages
Display a custom text message on the console for each alarm period. Dynamic tokens insert the next alarm time (#ALARM+1#), countdown (#TIMETOALARM+1#), current time (#NOW#), and more — updated automatically every period.
Per-Day Scope & Rules Overlay
AlarmIndexData, DateAndTimeDataFormatInEffect and TextData each accept multiple *scope|-prefixed lines so a specific day-of-week, day-of-month or date can override the default positional values without duplicating the full-year schedule. New OffsetRules and TextDataRules add a first-match-wins rule overlay with slot, t, w, nw, m, d, ld filters (and ! negation) for day-specific wording and minute offsets — e.g. a Jumu'ah text on Fridays or a longer Dhuhr offset during Ramadan. Resolution order: rules → per-day scope line → unscoped default.
Text-to-Speech
Console text is read aloud each time it changes using a pre-recorded word audio library. Record all required words with the built-in Ctrl+R console interface. Only 24 audio files (numbers 0–20, 30, 40, 50) are needed to cover all time announcements.
Fix Pronunciations
If the neural voice says a name, place or term wrong, correct it yourself — no phonetic codes. In the Pronunciations panel (device dashboard, cloud dashboard, or the Android app) type the word and how it should sound, press Preview to hear it, then Save. Plurals and possessives follow automatically; fixes are stored on the device and survive updates. Advanced users can pin raw IPA.
Pronunciation Workbench
The device’s /pronunciations page lists every unique word the system can say — from your announcement text, your templates and the announcements people type on the spot — and marks the ones the voice is only guessing at, so you can find the mistakes instead of waiting to hear them. Can’t respell a word? Say it: record it once or twice and the device works out the pronunciation, offers a few candidates in the announcement voice, and saves the one you pick as an ordinary dictionary entry. Your recording is only ever a target — it is never played on air. Changed the voice? Re-check my recordings runs every stored recording through the new voice and lists only the words it disagrees with — a derived reading is only the closest match for the voice it was derived against, and nothing else would tell you.
Voice Broadcast
Record an ad-hoc voice clip from the configured record device, preview it locally, then — after explicit confirmation — transmit it through the playback device at alarm priority, interrupting radio and ambient just like an Adhan. Available from the console (Ctrl+B) and as a dedicated card on the Web Remote dashboard.
Wide Format Support
Plays MPEG (MP1/MP2/MP3, layers 1.0–2.5), OGG, FLAC, WAV and AIFF. Wildcard filters on both filename and extension let you target exactly the files you want from each folder.
Fully Offline & Headless
Zero internet dependency once configured. Deploy on a Raspberry Pi with a one-command install script; a systemd service auto-starts Multilarm at boot with no keyboard or screen needed thereafter.
Multi-Platform
Native binaries for Windows x64 and Linux ARM 32-bit and 64-bit (including Raspberry Pi). Folder path tags ({app}, {home}, etc.) resolve automatically to the correct system paths on each platform.
Alarm Fade-In
Configurable fade-in for Adhan alarms. Gradually ramp volume from silence to target level over a set duration for a gentle wake-up experience.
Alarm Repeat
Play the same randomly-chosen alarm file multiple times per trigger with a configurable silence gap between repetitions. The full repeat sequence is treated as a single high-priority event — radio and ambient stay suppressed for the entire duration.
Volume Profile
Automatic volume changes driven by time-range rules. Each rule may carry an optional volume= override (e.g. 22:00-07:00,volume=0.3) that replaces the master volume during matching windows — ideal for quiet nights or busy-hour boosts.
Audio Health Check
Startup validation of all audio paths. Multilarm verifies that configured audio files and folders exist before entering the main loop, catching misconfigurations early.
Built-in Diagnostics
A one-click check-up battery that tells you what is working and what is not — around 30 pass/warn/fail checks across deployment, clock & schedule, audio content, cloud/network and hardware, each failure with a plain-language fix hint. Open http://<device-ip>:6580/diagnostics on any phone or laptop on the site network: the standard battery is silent and safe, while Guided commissioning mode steps an installer through the audible tests (test tone on every output, alarm sample, live announcement, microphone loopback, relay and bell) with heard/not-heard confirmations, then exports a printable site report. Also available at the console (Ctrl+Y), from scripts (Multilarm --diagnose, exit code = failing checks), and remotely from the cloud dashboard's Diagnostics card. Commissioning engineers can import the report into a portal job to auto-fill the checklist and stamp the certificate with the device's self-test result.
Automatic Fault Detection
Always-on self-monitoring with zero setup. A background sweep plus live error monitoring auto-detect program faults (repeated errors, speech engine trouble), peripheral faults (output device unplugged or shuffled, relay board unresponsive, emergency button unarmed, disk low, missing audio) and network faults (cloud connection failing, token rejected, MQTT broker unreachable). Faults appear on the cloud dashboard's Attention row and the diagnostics page, ride every status update and support bundle, email you on serious failures via the existing alerts, and clear themselves when the problem goes away.
Config Hot-Reload
Automatic reload when the config file changes. Multilarm watches Multilarm.config.xml and applies updated settings without requiring a restart.
TTS Notification Chime
Optional chime before speech announcements. Configure a tone audio file to play immediately before each TTS announcement for an audible heads-up.
Playlist History Log
Track-by-track log of virtual radio playback. Every file played is recorded with a timestamp to Multilarm.playlist.log for review and diagnostics. When an internet stream is in use, ICY StreamTitle metadata broadcast by the station is logged as STREAM | <title>.
Web Remote Control
Built-in HTTP server exposes a REST API and an HTML dashboard for monitoring and controlling Multilarm from a phone or browser on the same network. View status, adjust volume, skip tracks, test alarms and edit configuration live. Optional HTTP Basic Authentication protects access when credentials are configured.
Cloud Relay
Control Multilarm from anywhere in the world via the Cloud Dashboard. Uses HTTPS polling (no port forwarding needed). Supports multiple devices per account, live status monitoring, and full remote control. Accounts are set up personally — here's how to get one. PHP/MySQL backend with bcrypt auth, CSRF protection, and rate limiting.
Multi-Speaker Mirroring
Fan every playback stream (radio, alarms, TTS, ambient, quotes, Voice Broadcast) out to additional output devices via the MirrorDevices setting. Volume, fades and seeks stay synchronised across all mirrors, so every room hears exactly the same audio as the primary playback device.
Multi-Instance Zones
Run several Multilarm processes on one machine, each driving a different zone (room/speaker/device). The --config <path> command-line switch picks the config file per instance; give each zone its own AudioDevice, WebRemotePort and CloudDeviceToken and they run fully independently.
Multi-Room Audio
Several Multilarms on one site playing the same sound at the same moment. One device is the sending device — whatever it plays (a scheduled item, an announcement, the radio, a live microphone) is streamed to any device set to Room, which plays it in step while keeping its own schedule, its own emergency button and its own settings. Rooms find the sender by themselves on the local network, or can be pointed at an address across subnets. Each room corrects its clock against the sender and plays every chunk at the moment it was stamped, so rooms agree with each other to within a few milliseconds on ordinary wired or good wireless networks — and multilarm --rooms-probe measures that on your network and prints the numbers rather than asking you to take ours on trust. Off out of the box; opens no port until you turn it on.
Radio Track Skip
Skip the current virtual radio track and advance to the next in the shuffle with Ctrl+N from the console, or remotely via the Web Remote API. In stream mode the same shortcut tears down and reconnects the upstream feed instead.
Multilarm Box Hardware
Turn a Raspberry Pi into a complete institutional audio appliance: ring a physical school/mosque bell on schedule through a 4-channel USB relay board, wire an emergency broadcast button to a GPIO pin (looped top-priority audio + full schedule suppression until reset), and send zone-targeted announcements that mute the other zone's amplifier while they play. Live relay control and an emergency drill button on the Web Remote's Hardware panel. All off by default.
Next Alarm Countdown
The console title bar continuously shows a countdown to the next scheduled alarm (e.g. “next alarm in 2h 14m”), updated automatically every minute.
Multilarm Network (included)
A companion that watches the network the box sits on, installed and running as part of every Multilarm installation on Windows, Linux and Raspberry Pi. It discovers every connected device, names manufacturers from a built-in offline copy of the IEEE registry, runs periodic internet speed tests, and — using a fixed set of plain-language rules (no AI) — tells you in plain English when something's wrong: “the internet is down, your equipment is fine, contact your provider”, a device you're watching has dropped, or your speed is well below what you pay for. It is read-only, runs unprivileged with zero setup (it reuses the device's cloud token), stays completely idle until the device is paired, and critical warnings arrive on the same email/Telegram alerts you already use. Full details →
Installation
Use the MSI installer for the simplest setup on 64-bit Windows. It bundles the required .NET framework, multilarm_audio.dll audio engine, and all resource files including Adhan, bleep, ambient and TTS audio.
Manual installation: Download the executable and resource ZIP. Extract the ZIP to the application root; multilarm_audio.dll ships alongside Multilarm.exe (no system-folder install needed).
Flashable Raspberry Pi image (easiest): download the ready-made SD-card image with Multilarm pre-installed, flash it with Raspberry Pi Imager or balenaEtcher onto an 8 GB+ microSD card, and boot the Pi with a screen and keyboard attached. A one-time first-boot wizard sets up Wi-Fi, the cloud token and audio (DAC HAT or Bluetooth speaker), then Multilarm starts automatically as a service on every boot. Default login: multilarm / multilarm (change it on first login).
Download the Raspberry Pi image (.img.xz)
Or install onto an existing Linux system: tested on Raspberry Pi OS / Debian 12 (bookworm) and 13 (trixie). The automatic script installs 64-bit audio drivers on ARM64, 32-bit on all other ARM systems.
One command (Raspberry Pi OS and Debian): this does exactly what the three numbered steps below do — installs the signing key, adds the repository, then installs the package. Nothing it downloads is executed, it prints every command before running it, and it stops with a plain reason rather than half-installing if the machine is not one we build for.
curl -fsSL https://multilarm.com/install.sh | shCautious about piping a script into a shell? You should be. Read it first — install.sh is about a hundred lines and is the same file the command above fetches — or just run the three steps yourself.
APT package (recommended on Raspberry Pi OS and Debian): add the Multilarm repository once, then install and update Multilarm with the same apt commands you use for everything else. Packages are signed; ARM 64-bit (arm64) and ARM 32-bit (armhf) are both provided.
curl -fsSL https://multilarm.com/apt/multilarm.gpg | sudo gpg --dearmor -o /usr/share/keyrings/multilarm.gpgecho "deb [signed-by=/usr/share/keyrings/multilarm.gpg] https://multilarm.com/apt stable main" | sudo tee /etc/apt/sources.list.d/multilarm.listsudo apt update && sudo apt install multilarmThen start it for your user (it runs as a per-user service so it can reach your sound device):
systemctl --user enable --now multilarmOn a headless Pi that nobody logs into, also allow the user service to run without a session, or it will not come back after a reboot:
sudo loginctl enable-linger $USERLater updates are just sudo apt update && sudo apt upgrade. Config and logs live in ~/.local/share/multilarm, so removing the package never deletes your settings.
Note: Multilarm is not part of Debian or Raspberry Pi OS and is not distributed by them — the repository above is operated by us.
Automatic installation (script):
sudo curl -s -L https://bit.ly/multilarm-linux | bashLaunch Multilarm:
$HOME/MultilarmInstall as a service (auto-start at boot):
sudo curl -s -L https://bit.ly/multilarm-service | bashsystemctl --user status multilarm.service --nopager --fullsystemctl --user stop multilarm.service
systemctl --user daemon-reloadsystemctl --user disable multilarm.service
rm ~/.config/systemd/user/multilarm.service
systemctl --user daemon-reloadBluetooth audio (replace MAC address):
sudo curl -sL https://bit.ly/RPiConfig-BTAudio | bash -s AA:BB:CC:DD:EE:FFIQAudio DAC Pro HAT:
sudo curl -sL https://bit.ly/RPiConfig-DACProHAT | bashARM 64-bit Binaries — ARM 32-bit Binaries — Install scripts & Pi configs
Configuration
Multilarm.config.xml
All settings live in Multilarm.config.xml in the application root directory. The application must have write access to this directory. On first run with no config file, defaults are written automatically. Delete the file to reset to defaults. XML tags are case-sensitive in <Tag>Value</Tag> format. Do not use line feeds as delimiters in any field other than TextData (setting 20).
Two settings were added for room listening. ListenEnabled (default False) lets the device measure the room and recognise a smoke alarm; clips are measured and deleted immediately and no audio is retained or sent anywhere. AdaptiveGainEnabled (default False) matches scene announcements to the measured room level. See Listening to the room.
The web console no longer ships with a default password. WebRemoteUsername and WebRemotePassword now default to empty instead of admin / 123456. Blank credentials bind the console to loopback only, so a fresh install has no network surface until you consciously set a username and password. Existing installations are unaffected — whatever you already set is read exactly as before.
The default configuration schedules Adhan throughout the day, all year, for UK Sheffield prayer times, with ambient sound playing for 10 seconds every 3 minutes.
What the Configuration Generator can do for you
It is not only a form over the XML. Most of the work of setting Multilarm up is done by sub-tools inside it, and nearly every “how do I…” question has an answer here:
| Set up a new device from scratch | Start from a preset → Guided setup wizard (Mosque, School, Care home, Office/Factory, Home, Cafe/Restaurant, Gym, Warehouse, Church, Museum) |
| Find a setting without knowing its name | 💬 Plain English labels (on by default) — 🔧 Expert puts the field numbers back |
| Get prayer times for your own city | Salat Calendar Generator — computes the year from your coordinates |
| Load a term timetable or event calendar you already have | Import .ics — from Outlook, Google Calendar, Apple Calendar |
| See the year as a grid instead of one long string | Visual Builder with undo/redo, month navigation and fill-month/fill-year |
| Add the same times across many days at once | Calendar Quick Add — whole year, one month or a date range, filtered by weekday |
| Shift every time by a few minutes | ± Apply to All — wraps correctly past midnight |
| Write a schedule or overlay rule without learning the syntax | the Rule Builder on that field — compose, preview live, then add |
| Change a device that is already running | Live Connection — load from and save back to a running Multilarm; it applies in about two seconds |
| Play several files for one announcement | Audio sequences — source specs such as >all, >seq, chained with + |
| Print a timetable for the notice board | Print Calendar PDF in the Salat generator |
Every field also carries its own Help button with the full reference — meaning, type, range, default and worked examples — plus validation as you type, and insert buttons for the {app} / {home} / {docs} path tags that make one config work on Windows, Linux and a Raspberry Pi. Whichever way you save, every tag is written, so a saved file is always complete.
Open it on the web, from the offline copy that ships with Multilarm, at /config on the device itself, or from the cloud dashboard — it is the same tool in all four places. Full walkthrough in the in-app manual under Tools → The Configuration Generator, or watch the 16-minute video tutorial — chapter 4 covers the wizard, the calendar generator and the import.
Prayer times for your own city — the Salat Calendar Generator. You do not need a timetable from anywhere else. Inside the Configuration Generator, enter your latitude and longitude (or tap 📍 Detect Location), pick the year, your calculation method — MWL, ISNA, Egypt, Makkah (Umm al-Qura) or Karachi — your Asr madhab (Shafi or Hanafi) and your high-latitude rule, then press Generate Calendar and insert the result into DateAndTimeData (field 09). A full year of Fajr, Sunrise, Dhuhr, Asr, Maghrib and Isha is computed in your browser — the calculation library is embedded in the page, so nothing is fetched from any prayer-time website and it works with no internet connection. Above 48°N (the UK and similar) choose the 1/7 of Night rule; MWL + Hanafi Asr + 1/7 of Night is the combination most UK masjids use. If your masjid follows its own printed sheet, you can paste that into field 09 instead.
Click any row to expand its description.
When True, DateAndTimeData contains alarm times for a single day with no date field at all. The entire dataset repeats every day.
Play to This Device
Turn a Multilarm into something a phone, tablet or PC on the same network can send sound to — a playlist, a recorded message, a radio app — without touching the Multilarm itself. It appears by name in the “play to” list of any app that speaks DLNA / UPnP AV, and what arrives becomes the background sound, so announcements still duck it, priority still interrupts it and an emergency still overrides it. AirPlay 2, Bluetooth A2DP and Spotify Connect are deliberately not supported: the first two have no implementation a proprietary product may link to (and AirPlay needs an Apple MFi licence), the third needs a commercial Spotify SDK licence — for Bluetooth, pair the phone with the operating system and take the audio in on the line input. Off out of the box; opens no port and advertises nothing until you turn it on, and an allow-list is there because DLNA itself has no password.
When True, DateAndTimeData covers one week. The date field is the first three letters (or full name) of the day — e.g. mon, fri (case-insensitive) — recycled each week.
When True, DateAndTimeData covers one month (ideally 31 entries). The date field is the day-of-month number, recycled every month. Only one of RecurEveryMonth, RecurEveryWeek or RecurEveryDay should be True; priority is Month > Week > Day. When all three are False, the full-year dataset applies.
When True, the date field is treated as MM-DD (American style) rather than the default British DD-MM.
Character(s) marking the start of the date field in DateAndTimeData. Not evaluated when RecurEveryDay is True.
Character(s) separating the day and month values in the date field. Only evaluated in full-year mode (all three Recur flags False).
Character(s) separating the date field from time entries, and separating each time entry within DateAndTimeData.
When True, automatically applies UK BST/GMT daylight saving correction during the last weeks of March and October. Only active in full-year mode.
The core scheduling dataset. Each entry: DateIdentifier + date + time fields delimited by TimeDelimiter. Times must be in ascending order; any time with a lower hour than the previous is auto-parsed as PM. Post-midnight times use 00:mm, not 12:mm.
Example — 1 January with six prayer times:
*1-1|6:26|8:20|12:11|1:44|4:00|5:48Dynamically expands time data each day using 1-based index references with +/- minute offsets. Effective list is then sorted ascending. Allows a single prayer-time dataset to generate offset alarm times and use different text without duplicating data.
Example: default value applied to 6:26|8:20|12:11|1:44|4:00|5:48 yields:6:21|6:26|8:20|8:30|12:01|12:11|1:44|3:53|4:00|5:48
Per-day scope lines (optional). The value may contain multiple newline-separated lines. Lines prefixed with *scope| (scope grammar matches AlarmIndexData: weekday, day-of-month, day-month, comma-joined lists) override the unprefixed default line when today matches. Most-specific match wins. Lets you reshuffle alarm slot timing on specific days — e.g. a longer fifth-slot offset on Fridays — without duplicating the whole DateAndTimeData year.
Optional rules-based overlay on DateAndTimeDataFormatInEffect, evaluated per output slot. Rules are tried top-to-bottom and the first match wins; if no rule matches, the positional value from the DateAndTimeDataFormatInEffect line in effect for the day is used as before. Leave empty to disable.
Rule format: <payload>;<filter>[,<filter>...]
Payload reuses DateAndTimeDataFormatInEffect grammar: N (copy source slot N), N+M (slot N plus M minutes), N-M (slot N minus M minutes).
Filters (ANDed within a rule):
slot=N | Output slot index being resolved (1-based) |
t=HH:MM or t=HH:MM-HH:MM | Source slot fire time (point or range) |
w=mo,tu,we,th,fr,sa,su | Weekday(s) |
nw=n | n-th occurrence of the weekday in the month |
m=1..12 or m=jan..dec | Month(s) |
d=1..31 | Day of month |
ld | Last day of the month |
! prefix | Negate any filter (e.g. !w=sa,su) |
Resolution order across all three mechanisms: rules → per-day scope line → unscoped default line.
5+10;w=fr,slot=5
1;!w=sa,suOne or more folder paths containing alarm audio files, delimited by |. The ambient file and zero-length files are excluded. Only the top directory is searched — add subfolders as separate entries if needed. Use folder tags such as {app}, {home} etc. for cross-platform paths — see Tips & Tricks for the full tag reference. An entry may also be a single file, a filename pattern (bell*.mp3), a folder with a playback mode ({app}\Adhan>all, >shuffle, >seq), or several of those chained with a space-padded + — see SequenceGapMs (74).
File format filter for alarm audio. Join multiple formats with ; — e.g. wav;mp3. Wildcards allowed in both filename and extension — e.g. *abc.mp*.
Maps each time slot from DateAndTimeData to a folder index (1-based) from AlarmPath. A random file from the mapped folder plays at runtime. With default AlarmPath: 1 = Adhan, 2 = Bleep.
Example: times 6:26|8:20|12:11|1:44|4:00|5:48 with index 2|1|2|2|2|1 plays a Bleep at 6:26, Adhan at 8:20, and so on.
Per-day scope lines (optional). The value may contain multiple newline-separated lines. Lines prefixed with *scope| override the default line when the current day matches. Scope grammar mirrors DateAndTimeData: *fr| (Friday), *15| (15th of any month), *15-10| (15 October), *mo,we,fr| (Mon/Wed/Fri). Most-specific match wins; the unprefixed line is the default fallback. Example — different first-slot folder on Fridays:
2|1|2|2|2|1|1|2|1|1
*fr|3|1|2|2|2|1|1|2|1|1Optional rules-based overlay on AlarmIndexData, evaluated per fire before the positional value. Rules are tried top-to-bottom and the first match wins; if none matches, the day's AlarmIndexData slot value (after per-day scope resolution) is used. Leave empty to disable.
Rule format: <payload>;<filter>[,<filter>...]
Payload: the alarm-folder index (1-based, into AlarmPath) the matched slot resolves to.
Filters: identical to OffsetRules/TextDataRules (slot, t, w, nw, m, d, ld; ! for negation). The t= filter matches the actual fire time of the slot being evaluated.
Resolution order: rules → per-day scope line → unscoped default line.
3;w=fr,slot=3
4;m=3-4,slot=4Duration in milliseconds for alarm fade-in from silence to target volume. A value of 0 starts playback at full volume instantly. Values of 1000–3000 are recommended for a gentle wake-up effect.
Number of times the same randomly-chosen alarm audio file plays per trigger. A value of 1 is the original single-play behaviour. When greater than 1, the same file replays AlarmRepeatCount times with AlarmRepeatGap (43) seconds of silence between plays. The full repeat sequence is treated as one alarm event — radio and ambient remain suppressed for the entire duration.
Silence gap in seconds inserted between successive alarm plays when AlarmRepeatCount (42) is greater than 1. Only meaningful when repeating; ignored when AlarmRepeatCount is 1.
When True, reads console text aloud whenever it changes (at each alarm transition), using the word audio library in TTSPath.
Console text displayed between successive alarm times, index-matched to DateAndTimeDataFormatInEffect time fields. Corresponding time value represents the end of text display interval, not the start. Supports dynamic tokens:
#ALARM+1# | Next alarm time |
#TIMETOALARM+1# | Time remaining until next alarm |
#ALARM+2# | Alarm after next |
#TIMETOALARM+2# | Time remaining until alarm after next |
#NOW# | Current time in 24-hour HH:MM format |
Per-day scope lines (optional). The value may contain multiple newline-separated lines. Lines prefixed with *scope| (same scope grammar as DateAndTimeData/AlarmIndexData/DateAndTimeDataFormatInEffect) replace the unprefixed default line on matching days. Most-specific match wins. Handy for day-specific wording — e.g. a Jumu'ah text on Fridays — without rewriting the whole text group.
Character(s) separating entries in TextData, enabling index-matching to time slots.
Optional rules-based overlay on TextData, evaluated per fire before the positional value. Rules are tried top-to-bottom and the first match wins; if none matches, the day's TextData slot value (after per-day scope resolution) is used. Leave empty to disable.
Rule format: <payload>;<filter>[,<filter>...]
Payload: literal replacement announcement text for the slot being resolved. Supports the same tokens as TextData (#ALARM+1#, #TIMETOALARM+1#, #ALARM+2#, #TIMETOALARM+2#, #NOW#).
Filters: identical to OffsetRules (slot, t, w, nw, m, d, ld; ! for negation). The t= filter matches the actual fire time of the slot being evaluated.
Resolution order across all three mechanisms: rules → per-day scope line → unscoped default line.
Jumu'ah Mubarak. #ALARM+1# Dhuhr.;w=fr,slot=3
Ramadan Kareem. Iftar at #ALARM+1#.;m=3-4,slot=4Folder containing the recorded word audio library for TTS. Only the top directory is searched — subfolders are not included. Use folder tags such as {app}, {home} etc. for cross-platform paths — see Tips & Tricks for the full tag reference.
File format filter for TTS audio files. Supports wildcards in extension (e.g. mp*) and multiple formats with ;.
Path to a chime or tone audio file played immediately before TTS speech announcements. Leave empty to disable the chime. Supports folder tags ({app}, {home}, etc.) for cross-platform paths. Takes the same source-spec grammar as AlarmPath (12), so a multi-tone chime is just a folder plus a mode — {app}\Adhan\Bleep>all plays every tone in filename order, with SequenceGapMs (74) between them, before the speech.
Selects how spoken announcements are produced.
Builtin— the original per-word concat path. Reads each word from the audio library at TTSPath. Fastest and lowest CPU, but every word needs a hand-recorded file for natural output. This is the default.Kokoro— renders the entire announcement in one pass through the Kokoro 82M neural voice (the KokoroVoice). Most natural-sounding option; requires the Kokoro ONNX, the OpenPhonemizer phoneme dictionary, and the combined voices file installed. The TTSChimePath chime still plays first. Apache 2.0 / MIT licensed — no GPL, no espeak. Falls back to Builtin if any model file is missing or the engine fails to start. Numbers, dates, times, money and common symbols in your text are spoken naturally —5→“five”,5:30→“five thirty”,2024→“twenty twenty four”,$5.50→“five dollars and fifty cents”,50%→“fifty percent” — so you can type plain digits and symbols without spelling them out.KokoroFillsWords— runs the concat path at runtime (so chime/timing/cache semantics match Builtin), but at startup uses Kokoro to auto-render every harvested word into TTSPath in TTSFileFormat. The fill is also reachable on demand: in the console pressCtrl+R→K; over LANPOST /api/tts/fillwith body{"confirm":true}; in the cloud dashboard click the “TTS Word Library (Kokoro)” card buttons. Passoverwrite=trueto replace existing recordings (destructive).
All three modes hot-reload — switching this value in Multilarm.config.xml takes effect on the next announcement without a restart.
Name of the Kokoro voice used when TTSEngine is Kokoro or KokoroFillsWords. Voices are loaded from the combined voices-v1.0.bin file shipped with the model. Common names: bm_george, bm_lewis (British male); bf_emma, bf_isabella (British female); am_michael, am_adam (American male); af_heart, af_bella (American female).
The model files (kokoro-v1.0.uint8.onnx, voices-v1.0.bin, kokoro.vocab.json, g2p.phoneme_dict.json) ship bundled inside the Multilarm executable and are auto-extracted next to the exe on first launch — nothing to download or install. (You can also drop overrides in the exe folder or %LOCALAPPDATA%\Multilarm\models\.) Works on every platform Multilarm ships for, including 32-bit ARM. Ignored entirely when TTSEngine is Builtin.
Speed multiplier passed directly to the Kokoro ONNX speed input. 1.0 is the natural pace baked into the voice; higher values speed up, lower values slow down. Default 1.0 — the voice's natural pace.
0.8–0.9: deliberate — good for elderly audiences or noisy rooms.1.0: natural — the voice's baked-in pace.1.1–1.3: brisk — good for short announcement windows.
Values outside 0.2–3.0 are clamped to the band at load time. Hot-reloads — the next announcement uses the new speed without restarting Multilarm. Ignored when TTSEngine is Builtin.
Length of the silent gap inserted between sentence chunks when Kokoro synthesises a multi-sentence announcement. Useful for letting listeners absorb each sentence before the next begins. Set higher for elderly or non-native audiences; set to 0 for very short announcements where the pause feels unnatural.
Ignored when TTSEngine is Builtin.
When True, plays a random-duration clip from AmbienceFile at the interval set in AmbienceInterval.
Full path (including filename and extension) to the ambient sound file. A clip of the duration set in AmbienceDuration is played from a random position within the file at each interval. Use folder tags such as {app}, {home}, {docs} etc. for cross-platform paths — see Tips & Tricks for the full tag reference.
Duration in seconds to play from the ambient file each time it triggers. Playback starts at a random position in the file.
Time in seconds between successive ambient sound playbacks.
Selects the radio source during RadioScheduleRules windows.
Local— shuffle RadioFolder as a virtual radio station. RadioStreamURL is ignored.Online— open RadioStreamURL via the miniaudio HTTP/ICY stream client. On connection failure or mid-window drop, falls back to RadioFolder shuffle so the device doesn't go silent — the fallback is logged toMultilarm.error.logand emits aradio.stream-fallbackwebhook. The stream is retried every ~10s while fallback is active.Disabled— radio off entirely.
Legacy boolean configs are accepted: True loads as Local, False loads as Disabled. Values are persisted in canonical form on the next save.
Root directory of the audio library used by the virtual radio. All audio files matching RadioFileFormat under this folder and its subfolders are included. The player uses a subfolder-aware shuffle: it visits subfolders in a freshly randomised order each round, selecting one file per subfolder before any subfolder repeats, so tracks interleave and no file repeats until the entire library is exhausted, at which point the directory is rescanned and the cycle restarts. Use folder tags such as {app} for cross-platform paths. When RadioStreamURL is set, the stream takes precedence over this folder; the folder is then used as the automatic fallback if the stream fails.
Shoutcast/Icecast stream URL used when PlayRadio is Online. Multilarm opens this stream via the miniaudio HTTP/ICY client during every active window in RadioScheduleRules. Ignored when PlayRadio is Local (folder-only) or Disabled. Useful for mosques and institutions that want to rebroadcast a 24/7 Quran or Islamic radio station.
Fallback and reconnect: in Online mode, if the connection fails at the start of a window or drops mid-window, the radio falls back to RadioFolder shuffle automatically so the device does not go silent, retries the stream every ~10 seconds, and logs the event to Multilarm.error.log plus a radio.stream-fallback webhook. Schedule rules, master volume, and volume profile rules apply identically to both sources.
ICY metadata: track titles broadcast by the station are appended to Multilarm.playlist.log as STREAM | <title> lines.
Skip behaviour: Ctrl+N (and the dashboard Skip button) tear down and reconnect the stream while in stream mode — useful when the upstream feed has stalled. In folder mode the same shortcut still advances to the next shuffled file.
The default points at qurango.net's main 24/7 Quran feed but is only consulted when PlayRadio = Online.
File format filter for the virtual radio library. Supports multiple formats joined with ; (e.g. mp3;flac) and wildcards in both filename and extension (e.g. *abc.mp*).
Defines when the virtual radio is active. Multiple rules are separated by ;; the radio plays if any rule matches. Each rule takes the form:
HH:MM-HH:MM[|HH:MM-HH:MM][,filter=value][,!filter=value]Multiple time ranges within a rule are separated by | and merged where they overlap. Filters:
m= | Month(s) 1–12. Ranges (m=3-6) and comma-lists (m=1,3,12) accepted. * or omitted = all months. |
d= | Day(s) of month 1–31. Ranges and comma-lists accepted. |
w= | Weekday(s). Two-letter codes: su mo tu we th fr sa. Ranges (e.g. w=mo-fr) wrap correctly across Sunday. |
nw= | Nth weekday of the month. E.g. nw=2mo = second Monday; nw=lastfr = last Friday. |
ld | Last day of the month only. |
! prefix | Exclusion filter. E.g. !w=su excludes Sundays. |
Midnight-crossing ranges (e.g. 22:00-02:00) are handled correctly. Setting both endpoints equal (e.g. 00:00-00:00) activates the radio for the full 24 hours.
Example: 08:00-20:00,w=mo-fr;09:00-17:00,w=sa,!m=8 — weekday office hours plus Saturday mornings except August.
When True, plays a random speech segment from QuoteFile at the interval set in QuoteInterval. The QuotePlayer detects silence boundaries in the audio file to select a clean, natural-sounding excerpt.
Full path (including filename and extension) to the audio file used for random quote playback. A random full speech segment is selected at each interval. Use folder tags such as {app} for cross-platform paths. Supports MP3, MP2, MP1, OGG, WAV, AIFF.
Time in seconds between successive quote playbacks.
Boundary detection is automatic. Multilarm scans QuoteFile once with an adaptive silence-detection algorithm and writes a <QuoteFile>.boundaries.json sidecar next to it. Subsequent runs reload the cached tiers (word / sentence / paragraph). Delete the sidecar to force a rescan after editing the source audio. No manual threshold or gap-duration tuning is required.
Time-range schedule rules controlling when periodic quote playback is active (same format as RadioScheduleRules). When the current time does not match any rule, quotes are skipped even though the timer still fires. Use 00:00-00:00,m=* to allow quotes at all times.
Selects the audio output device. -1 = system default. 0 = disables audio output entirely. 1 and above = 1-based index of available output devices.
Selects the audio input device for TTS word recording. -1 = system default. 0 and above = 0-based index of available recording devices.
Additional audio output devices to mirror every playback stream onto. When set, every track played by Multilarm — virtual radio background, crossfade transitions, quote segments, ambient audio, Adhan alarms, TTS speech and Voice Broadcast transmits — is opened once on AudioDevice (Playback) (23) and again on each device listed here. All mirrors stay volume-synchronised, fade-synchronised and seek-synchronised with the primary stream, so every mirror room hears exactly what the primary playback listener hears.
Format: pipe-delimited list of integer device indices sharing the same index space as AudioDevice (Playback) (shown in the startup log). Example: 1|3 fans audio to devices 1 and 3 in addition to the primary device. Mirror devices already initialised are silently reused. Devices that fail to initialise (unplugged, busy, invalid index) are logged as a yellow warning and skipped; the remaining valid mirrors still work.
Use cases: same audio to multiple amplifiers/speaker groups around a building; redundant output (main PA + backup monitor); bridging a USB DAC plus onboard audio simultaneously.
Master playback volume applied to all audio routed through ManagedPlayer (alarms, TTS, quotes, radio, ambience). 1.0 is full volume; 0.0 is silent.
Duration of the volume crossfade (in milliseconds) when the virtual radio transitions between background tracks. A value of 0 disables crossfading. Typical range: 500–3000 ms. Also applies when background playback is interrupted and later resumed.
Time-range rules controlling playback volume through the day. Each rule uses the same syntax as RadioScheduleRules plus an optional volume=<0.0-1.0> filter. When a rule matches, its volume= overrides the master Volume; rules without volume= let the master setting apply. Leave empty to disable. Example: 22:00-07:00,volume=0.3;12:00-14:00,volume=0.6,w=mo-fr
When True, starts a built-in HTTP server that exposes a REST API and HTML dashboard for remote control. Access the dashboard from any browser on the same network at http://<host-ip>:<port>/. The API allows monitoring status, adjusting volume, skipping tracks, testing alarms, recording and transmitting voice broadcasts, and editing configuration live. If enabled without credentials, the server binds loopback-only for safety.
TCP port for the Web Remote HTTP server. The server first attempts to listen on all network interfaces (http://+:port/); if that fails (e.g. no admin rights), it falls back to http://localhost:port/. On Windows, to listen on all interfaces without elevation, run: netsh http add urlacl url=http://+:6580/ user=Everyone
Username for HTTP Basic Authentication on the Web Remote API and dashboard. When both WebRemoteUsername and WebRemotePassword are set, all requests must include a valid Authorization: Basic header. Leaving either empty triggers loopback-only binding so the server is not exposed on the LAN.
Password for HTTP Basic Authentication on the Web Remote API and dashboard. Both WebRemoteUsername (51) and WebRemotePassword must be set for LAN access to be active. The password is transmitted as Base64-encoded text — for security, only use over trusted local networks or behind HTTPS.
The unique device token that authenticates this Multilarm instance with the Multilarm Cloud relay at https://multilarm.com/cloud. Cloud Relay is always enabled when this token is set — leaving it empty is the only way to disable the relay. Generate the token by adding a device in the Cloud Dashboard (accounts are set up personally — here's how to get one). Treat the token as a password — anyone with it can control your Multilarm instance. If compromised, remove the device from the dashboard and add a new one. You don't have to edit the config file by hand: press Ctrl+K at the device console and paste the token (validated, saved and applied immediately), or run Multilarm --cloud-token <token> on headless installs — a running instance picks the change up within ~2 seconds. The dashboard's token reveal even has Windows command / Linux command buttons that copy that complete command for you — paste it into a terminal opened in the Multilarm program folder. Cloud Relay is a subscription service paid by bank transfer or invoice (no card needed; local schedules always keep running without it) — see pricing. Billing runs itself from there: a renewal invoice (PDF) is emailed about a month before your access date, reminders follow as it approaches, every confirmed payment gets an emailed receipt, and a late payment triggers a clear grace-period notice long before anything pauses. Signed in, the dashboard header has Get help (attaches a sanitised device-diagnostics bundle for you — secrets stripped on the device) and My account (plan, renewal date, device usage, invoice PDFs); forgot your password? reset it yourself from the sign-in page.
Free-space floor in megabytes for the drive hosting Multilarm's audio library. Surfaced in the cloud-relay status push as health.disk and on the Ctrl+I runtime status readout. When free space drops below this value the Cloud Dashboard fires the "disk low" alert. Set to 0 to disable the device-side flag entirely — the cloud then never sees diskLow=true and never fires the alert.
Human-friendly display label for this Multilarm instance. Pure UI text — it has no effect on scheduling, audio, Hub routing, or peer matching. The value appears in exactly three places: the card text on the Multilarm Hub dashboard (/hub), the "name" field of this instance's heartbeat JSON under %LOCALAPPDATA%\Multilarm\instances\<InstanceId>.json, and the Ctrl+I runtime status readout.
How multiple instances stitch together (hint: not by name). Every running Multilarm drops one JSON file into the instances\ directory named after its InstanceId, refreshed every 15 s. Any instance in Hub mode lists peers by enumerating that directory and keeping every file whose heartbeat is within the last 60 s. Each surviving file becomes one card on /hub, labelled with its InstanceName but keyed by InstanceId. Because deduplication is on ID, duplicate names are allowed — two instances both called Kitchen render as two separate cards with identical labels.
When to change it: whenever you run more than one Multilarm instance side-by-side (multi-zone deployments on one PC, or multiple PCs on the LAN). The default label is the active config filename (e.g. Multilarm for Multilarm.config.xml, kitchen for kitchen.config.xml), which becomes unhelpful once you have several rows to tell apart. Examples: Kitchen PC, Garage Pi, Broadcast Room, Main Hall PA. Safe to edit at any time — hot-reload rewrites the heartbeat JSON on the next tick (≤15 s) and the Hub card text updates on its next refresh. Changing the name never orphans heartbeat history, because the stable key is InstanceId (auto-generated on first run and persisted in a sidecar <activeconfig>.iid file next to the config — never written into config.xml), not this label.
Worked example — three zones on one PC:
| Config file | InstanceName | Hub card label |
|---|---|---|
kitchen.config.xml | Kitchen PC | Kitchen PC |
garage.config.xml | Garage Pi | Garage Pi |
hall.config.xml | Main Hall PA | Main Hall PA |
Whichever instance is in Hub mode (started with --hub or promoted with Ctrl+H) shows all three cards; clicking a card proxies through to that instance's port and basic-auth credentials, both read from its heartbeat JSON.
Optional override for the path to the External Trigger API profiles & tokens JSON file. Empty (default) derives <configBaseName>.triggers.json next to the active config file (e.g. kitchen.config.xml → kitchen.triggers.json), using the same write-privilege fallback chain as the config XML. Supports path-tag expansion when overridden. The LAN endpoints /api/trigger and /api/trigger-audio are always exposed when Web Remote is running, and are gated entirely by what is in this file — no tokens defined means every request gets 401.
multilarm/trigger) and every subscriber of that topic receives it. Multilarm subscribes to your broker and fires the matching External Trigger API action. Use this transport when your other equipment already publishes to a broker.When True, connects to the customer-provided MQTT broker on startup and subscribes to <MqttBaseTopic>/trigger (JSON) and <MqttBaseTopic>/trigger-audio/+ (raw bytes) for inbound External Trigger API messages. Publishes a retained heartbeat to <MqttBaseTopic>/status and per-fire envelopes to <MqttBaseTopic>/events. Client ID auto-derived as multilarm-<InstanceId> — stable across restarts so broker per-client ACLs work without extra config.
MQTT broker hostname or IP address (no scheme). Required when MqttEnabled is True. Examples: mqtt.example.com, 192.168.1.10.
TCP port for the MQTT broker. The default is 1883 (plain MQTT). When MqttUseTls is True and the port is left at the default, the bridge automatically falls back to 8883 (MQTT over TLS).
When True, the MQTT bridge connects to the broker over TLS. If MqttPort is at the default 1883, it is automatically promoted to 8883 for the TLS connection.
Username for MQTT broker authentication, if required. Leave empty for anonymous brokers.
Password for MQTT broker authentication, if required. Stored as plain text in Multilarm.config.xml; protect the file accordingly.
Topic prefix used by the MQTT bridge. Subscribes to <base>/trigger and <base>/trigger-audio/+, publishes to <base>/status and <base>/events. Useful for multi-tenant brokers where each Multilarm instance needs an isolated topic root.
JSON array of outbound webhook endpoint objects. Each entry has shape {Url, Secret?, Events?, TimeoutMs?, Retries?, Headers?}. Multilarm POSTs JSON event envelopes to every configured endpoint whose Events filter matches (or whose Events is empty, meaning subscribe-to-everything). HTTPS or RFC1918 private-IP URLs only. Set to [] or leave empty to disable. Hot-reload safe: workers diff by Url, so an unchanged endpoint keeps its in-flight queue across config edits.
Date-scoped config switching. Pipe-delimited list of filename,rule pairs. Each rule uses the same time-range + date-filter syntax as RadioScheduleRules. Evaluated once at midnight; the first matching rule selects the config file for the day, otherwise the default Multilarm.config.xml is used. Missing or unparseable alternate files fall back to the default with a warning; the process does not crash. Example: multilarm.ramadan.xml,00:00-23:59,m=3|multilarm.weekend.xml,00:00-23:59,w=sa,su
Serial device of the Multilarm Box USB relay board and the feature's on/off switch — empty disables the relay entirely (same pattern as CloudDeviceToken). CH340-based boards enumerate as /dev/ttyUSB0 on the Pi; the Box provisioning script also installs a stable /dev/multilarm-relay udev symlink. The hardware contract is fixed in code: 9600 baud and channels 1=Bell, 2=ZoneMuteA, 3=ZoneMuteB, 4=EmergencyLed, 5=ZoneMuteC, 6=ZoneMuteD — wire the board to match (a 4-channel board covers bell + 2 zones + emergency LED; 3–4 zones need an 8-channel board). Leave empty until the board's byte protocol is confirmed with the Ctrl+G console test. Linux/Raspberry Pi feature; harmlessly ignored on Windows.
Byte framing the board expects — cheap CH340 boards (4- or 8-channel) ship two incompatible protocols. A0 = {A0, channel, state, checksum} (most LCTECH/SainSmart CH340 boards); FF = {FF, 01, channel} open / {FF, 01, 00} close-all (some ELEGOO boards). Confirm with the Ctrl+G relay test: if no channel clicks, switch protocol and retry. A wrong protocol is harmless — the board just ignores the bytes.
Point-in-time bell schedule. Each entry: HH:MM[,dur=NNNN][,date filters] — 24-hour fire time, relay pulse length in ms (default 1000, clamped 100–60000), and the same date-filter vocabulary as RadioScheduleRules. Bells pulse relay channel 1 only — no audio is played and announcements are never interrupted. Example school day: 08:45,dur=1500,w=mo-fr;12:00,dur=2000,w=mo-fr;15:15,dur=3000,w=mo-fr;
BCM GPIO number the emergency button is wired to and the feature's on/off switch — -1 disables it (same convention as PlaybackDevice). GPIO 17 (physical pin 11) is the documented wiring. Wire a momentary normally-open button between the pin and GND — Multilarm enables the internal pull-up itself, so no external resistor is required. Avoid GPIO 18–21 if a HiFiBerry DAC is fitted. A press interrupts all audio, loops EmergencyAudioFile at top priority, suppresses every scheduled alarm/announcement/bell, and lights the EmergencyLed relay channel until reset (hold the button 3 s, or use the web Hardware panel — whose Test button drives the identical chain without hardware). Debounce 500 ms and the 3 s hold are fixed in code. Linux/Pi only.
Audio file looped at top priority while the emergency is active. Any playable format; a short, clear file (≤30 s) loops best. Missing/empty file logs a warning and the emergency still suppresses the schedule and lights the LED — a silent emergency beats a crashed one.
Decides which announcements are zone-targeted. Same overlay grammar as TextDataRules with the zone name as payload: ZoneA;slot=7 sends the slot-7 announcement to Zone A only. Up to four zones (ZoneA–ZoneD): targeting a zone opens the mute relay of every other zone you use, so only the chosen zone is heard (ZoneMuteA–D on channels 2, 3, 5, 6). Two zones run on a 4-channel relay board; three or four need an 8-channel board. The mutes always release after the announcement, even if playback fails. First matching rule wins; announcements matching no rule play in all zones with zero relay activity. Bells always ring everywhere.
Master switch for the cloud dashboard / Android app “Start emergency drill” command. When True (default), an owner can start an emergency broadcast remotely (after a confirmation). When False, the device refuses a remote start — only the physical emergency button (EmergencyGpioPin) can begin one — while a remote reset is always honoured so a stuck emergency can still be cleared from afar. The on-device button and the LAN Web Remote Hardware panel are unaffected either way. Remote emergency over the cloud is best-effort (it rides the command poll and needs connectivity); the physical button stays the authoritative path. Only relevant when the emergency feature is configured.
Opt-in automatic updates. When True, the device checks the published version manifest (https://multilarm.com/multilarm/latest.json) about once a day and, if a newer build exists for its platform, installs it automatically — no dashboard command needed. Each auto-update takes the same safe path as the manual Update button in the dashboard: the download is SHA-256 verified, the previous binary is kept, and a watchdog rolls back automatically if the new version fails to come back online. A build that has just failed is not retried for 48 hours, so a bad release can never spin in a restart loop. When False (default), the device updates only when an owner clicks Update in the cloud dashboard. You can toggle this straight from the dashboard’s Software row — it is delivered to the device as this config field.
Silence between different audio files inside one announcement — between a bleep and the adhan, or between the tones of a multi-tone chime. Not to be confused with AlarmRepeatGap (18), which is the silence between repeats of the whole announcement; both apply on the same fire and are independent. Multi-file announcements are configured in the paths themselves: any AlarmPath (12) entry, and TTSChimePath (25), accepts a source spec <path>[>one|all|shuffle|seq][*count], and several sources chain with a space-padded + — e.g. {app}\Adhan\Bleep\ding.mp3 + {app}\Adhan plays a bleep then a random adhan. A plain folder path still means “one file at random”, so existing configs are unaffected.
Hard ceiling on one announcement — every file, every repeat. When it is reached the remaining files are skipped and the reason is logged. This is a safety net: pointing >all at a folder of hundreds of tracks would otherwise hold the speakers, suppress the radio, and block every alarm behind it for hours. Set 0 for no limit when a long announcement is deliberate (a full recitation as the alarm, say). The startup health check separately warns — without stopping anything — when one source resolves to more than 20 files.
Address of the phone system (PBX) this device registers with, so staff can page the building by dialling an extension from any handset. Port defaults to 5060. Empty means SIP paging is off — the same presence-is-enabled convention as RelayPort (66). SIP paging is a paid add-on: it needs an active Cloud Relay subscription with SIP enabled on the account, plus the separate Multilarm SIP companion downloaded from your account page. The companion is deliberately not part of the installer, so setting these fields on a device without it does nothing.
The SIP account Multilarm signs in as. Ask whoever runs your phone system for an ordinary extension — it needs no special privileges, only the ability to receive calls. Give it an obviously non-human name such as multilarm-pa so its purpose is clear in the phone system’s logs.
Password for SipUsername (77). Treated as a site secret like WebRemotePassword and MqttPassword: stored in the device config, but never returned by the status or config APIs (a read shows ********) and stripped from the configuration snapshots kept in the cloud. Restoring an older snapshot leaves the live password untouched rather than blanking it.
The number staff dial to make an announcement, e.g. 700. This is documentation rather than routing — the call reaches Multilarm because your phone system sends it to the SipUsername (77) account. Recording it here means the dashboard, the diagnostics report and the commissioning certificate can all tell an engineer what to dial without them digging through the PBX.
Which extensions may page. Separate with | or ,; a single trailing * is a wildcard (201|202, 30*, or * for anyone). An empty list rejects every call — deliberately the opposite of most settings here, because something that can speak to a whole building should not answer the world just because a field was left blank. Caller ID comes from your phone system, and a PBX that accepts outside calls can be made to present any number, so if external calls can reach this extension keep the list tight and ask your provider to block inbound calls to it.
When True (default) a permitted call is answered immediately and the caller is live on the PA. When False every inbound call is refused — a convenient temporary stop during an exam or an event without having to clear SipServer (76) and lose the rest of the configuration. Being answered is not the same as being heard instantly: if an alarm or emergency broadcast is already playing, the page waits for it to finish rather than cutting it off.
How long each registration with the phone system lasts before it is renewed. Two minutes suits almost every site; change it only if your phone system asks for something specific. Shorter means a dropped registration is noticed sooner but there is more traffic to the PBX; longer is quieter but after a phone-system restart there can be a gap where a call to the paging extension goes nowhere. Values outside 30–3600 are clamped.
The UDP port the SIP companion listens on. Leave at 5060 unless something else on the device already uses it. A fixed port matters for two practical reasons: a firewall rule needs to stay valid, and some phone systems send calls to a fixed address and port rather than to whatever contact the device last registered from. 0 lets the operating system pick any free port — workable when the PBX only calls back to the registered contact, but the port then changes on every restart, so a firewall rule written today stops matching tomorrow.
Lets the device measure how loud the room is and recognise the standard fire-alarm sound pattern. No audio is kept. Every twenty seconds a short clip is captured, measured and deleted before it is analysed — nothing is written to disk, nothing leaves the device, and there is no way to play any of it back. The feature produces numbers, not recordings; if you want audio kept that is RecordScheduleRules (86), a separate feature you turn on separately. The measurement feeds AdaptiveGainEnabled (85), drives the “room is louder/quieter than” automation triggers, and can raise an alert when a smoke alarm sounds somewhere nobody is present to hear it. Needs a capture device; on a device with no microphone it does nothing. Worth telling people about — in many places, and in most workplaces, people in a room are entitled to know it is being listened to even when nothing is kept.
Raises announcements in a noisy room and lowers them in a quiet one, so a message set for an empty hall is not inaudible once it fills up. Needs ListenEnabled (84) — with no measurement it changes nothing at all, silently. It never quietens an alarm or an emergency broadcast: the adjustment applies to scheduled announcements, the radio and ambience only, and anything at alarm or emergency priority plays at its configured volume whatever the room sounds like. The adjustment is bounded around your configured Volume (46), so a single loud bang cannot drive the PA to maximum.
When to record the room, using exactly the same grammar as RadioScheduleRules (38) and QuoteScheduleRules (42) — e.g. 09:00-10:00,w=mo-fr, or 00:00-00:00,m=* for continuous. Recordings are saved as WAV in a Recordings folder beside the device config, named by start time. Recording never interrupts playback — it only reads the microphone. It does yield the microphone, though: if an operator starts push-to-talk or a voice broadcast mid-recording the recording stops and the part already captured is kept, because a truncated recording is more use than none. It in turn takes the microphone from room listening. Recording a room is not the same as measuring it — it produces files that persist and can be listened to, and whether you may do that, and whom you must tell, depends on where you are and who is in the room.
How long a recording is kept before it is deleted automatically. The tidy-up runs whenever nothing is being recorded, so a device left alone keeps its own disk under control. 0 means keep everything for ever — honoured exactly, but continuous recording at the default quality is roughly 0.3 GB a day, so a year is over 100 GB. On an SD card that ends in a full disk, and a full disk is a device that cannot log, cannot update and may not start. For indefinite retention, copy recordings elsewhere on a schedule rather than letting them accumulate here. Values outside 0–3650 are clamped.
Which part this device plays in a multi-room group, where several Multilarms play the same sound at the same moment. Server carries on exactly as before and additionally sends a copy of everything it plays — a scheduled item, a spoken announcement, the radio, a live microphone — to any room that joins. Room plays what it is sent, while keeping its own schedule, its own emergency button and its own settings: multi-room adds a source of sound, it never takes the local one away. You need exactly one Server; two on a network is not something the software can detect for you. A room that loses the network goes quiet rather than guessing, because two ends of a building announcing different things is worse than one end announcing nothing. Takes effect on restart — changing role live would mean dismantling the audio path underneath whatever is playing, and Multilarm will not silence a room to apply a setting. An unrecognised value is treated as Off, never guessed.
The TCP port the sending device listens on and rooms connect to. It must be the same number on every device in the group. Automatic discovery uses the next port up (7452, UDP broadcast) and is deliberately not configurable, so there is only ever one number to get right. If a firewall sits between the devices, this is the port to allow. Multi-room is a local-network feature and is not intended to cross the internet — the traffic is uncompressed audio.
A shared word deciding which devices may join the group; set the same value on the sending device and every room. Blank means any Multilarm on this network may join — the right default for a house, the wrong one for an office, school or guest network. Be clear about what it is: a check, not encryption. The audio itself crosses the local network in the clear, deliberately, because it carries programme audio the building is already broadcasting aloud through its speakers and a certificate handshake in front of an emergency announcement would trade something that matters for something that does not. If the audio itself must be private, multi-room is not the feature to use.
Where a room looks for the sending device. Left blank, the room broadcasts a short question at startup and follows whichever sending device answers — the normal case, needing no configuration. Fill it in when discovery cannot work or should not be relied on: the devices are on different subnets or VLANs (broadcasts do not cross them), the network blocks UDP broadcast as most guest wireless and many managed switches do, or you simply want the room to be certain which device it follows. A room pointed at an address does not search; if that address does not answer it says so in the log and stays quiet rather than joining something else. Ignored on the sending device.
The deliberate delay a room adds before playing what it has been sent — the one number that buys network reliability, paid for in immediacy. Every room must use the same value: two rooms set differently are, by definition, out of step by the difference. The default of 400 is comfortable on ordinary wired or good wireless networks and unnoticeable for scheduled sounds, announcements and music. Raise it towards 800–1500 if a room stutters or drops out — that is almost always a weak or busy wireless link, and a larger buffer is the correct fix. Lower it towards 150–250 only on a wired network and only where the delay genuinely matters, such as a live microphone whose operator can hear a distant speaker while talking. Below roughly 150 ms on wireless you are asking every packet to arrive early every time, and the audible cost of missing that deadline is a gap — far more noticeable than the delay saved.
A label, and nothing more. It appears when the room joins or leaves, in the log at both ends, and wherever the sending device lists the rooms following it. It has no effect on routing or on which sounds a room plays. Use the names the building already uses — Kitchen, Warehouse, Reception — so a log line a year from now still says where something happened. Blank falls back to the device name (InstanceName, 55), which is usually the right answer already.
Makes this device appear on the local network as something a phone, tablet or PC can send sound to — it shows up in the “play to” or “cast” list of any app that speaks DLNA / UPnP AV (Android’s cast picker in many media apps, VLC, BubbleUPnP, foobar2000, Windows “Cast to Device”, Kodi, Plex, most NAS media servers). What is sent becomes the background sound, in the same place the Virtual Radio sits, so every existing rule still applies unchanged: scheduled items and announcements duck it, priority interrupts it, the volume profile shapes it and an emergency overrides it outright. A phone can never make the building quieter than the schedule intends. Casting and the radio want the same channel, so the most recent request wins and the radio resumes when the cast stops. AirPlay 2, Bluetooth A2DP and Spotify Connect are deliberately not supported — the first two have no non-GPL implementation available to a proprietary product and AirPlay additionally needs an Apple MFi licence, and the third needs a commercial Spotify SDK licence. For Bluetooth, pair the phone with the operating system of the machine running Multilarm and take the audio in on the line input. Takes effect on restart.
The name people see in their “play to” list. Name it after the space it fills rather than the machine — Main Hall Speakers, Shop Floor, Playground — because the person choosing it is looking at the room, not at your equipment list. Blank falls back to the device name (InstanceName, 55). Takes effect on restart.
The port the device description and control pages are served on. Discovery itself is the standard 1900/UDP and is not configurable, because a sender that cannot find the standard port cannot find the device at all. Change this only if something else on the machine already holds it. Values outside the range fall back to the default.
Who may send. Blank means anyone who can reach the port, which is how DLNA works everywhere: the protocol has no authentication of any kind, and that is a fact about the standard rather than a gap here. Where that matters, list the addresses allowed to control the device — either exactly (192.168.1.50) or as a prefix ending in a dot (192.168.1., meaning that subnet). A device that is refused is told so plainly and the refusal is logged. If sound through the building genuinely needs to be an authenticated act, leave CastEnabled off and use the Web Remote, which has accounts. Takes effect on restart.
Turns on a processing chain on each physical output: a level trim, up to eight tone filters, a delay and a peak limiter, in that order. This is what a separate rack DSP is normally bought for, and the three jobs it does are the three that decide whether a building’s announcements are intelligible — correcting the speakers you have, time-aligning a distant run so a word does not arrive twice, and holding peaks back so a horn is not driven past what it can take. Off means untouched, not “processed with neutral settings”: the chain is bypassed sample-for-sample, so an install that never opens this section sounds exactly as it did before the feature existed. The processing runs after the multi-room tap, so a room listening over a Multilarm link hears what this device played rather than this device’s amplifier correction and speaker delay. It shapes audio and can never start, stop or silence anything. Takes effect immediately.
A fixed level adjustment applied before everything else in the chain. Use it to match outputs to each other, not to set overall volume — that is Volume (46) and the volume profile (48). The usual case is a second amplifier that is simply louder than the first: trim it down a few dB and the two zones finally sound like one building. Every 6 dB is roughly a halving or doubling. Boost is available to +24 dB but gives the limiter and the ceiling more work; if you need a lot of it, the honest fix is the amplifier’s own gain control.
The tone controls, written out. Each band is type,frequency,gain,width and bands are separated by semicolons. type is one of peak, lowshelf, highshelf, lowpass, highpass; frequency is in hertz from 20 up to just under half the sample rate; gain is −24 to +24 dB and is ignored by the two pass filters, which cut rather than tilt; width is the Q, where 0.707 is the gentle textbook default, 3 is surgical and 18 is a notch. A worked example for speech through ceiling speakers: highpass,120,0,0.707;peak,3150,4,1.2;highshelf,8000,-6,0.707 — drop the rumble the speakers cannot reproduce, lift the consonant range that carries intelligibility, take the hiss off the top. These are the standard cookbook filters every measurement rig implements, so a curve worked out on other equipment behaves as you expect. A band the device cannot read is rejected in full and the whole EQ cleared rather than half-applied, with the reason logged — a typo that quietly leaves a high-pass off a 100 V line is the kind of fault discovered by ear, in front of a room.
Holds each output back so speakers at different distances reach a listener together. The order is positional: the first entry is the main output (PlaybackDevice, 43) and each entry after it lines up with the additional outputs (MirrorDevices, 45) in the order listed there. A short list is not an error — outputs it does not mention are simply not delayed. 0|35|70 leaves the main output on time and holds the second and third by 35 and 70 ms. Sound covers roughly a metre every 3 ms, and you delay the sound that would otherwise arrive first: a zone 20 m closer than another needs about 60 ms on the near zone. Getting this right is the difference between a corridor that echoes every word and one that simply sounds loud. Maximum 500 ms per output.
Catches peaks that would otherwise clip and rides them down instead. A clipped waveform carries far more high-frequency energy than the speech it came from, and that energy goes into the tweeter or compression driver as heat — clipping is how horn drivers die, so on a 100 V line feeding fixed installation speakers a limiter is cheap insurance for hardware nobody wants to get a ladder out for. It grabs in about 1.5 ms and lets go slowly, so one loud syllable does not duck the rest of the announcement behind it. Measured on the bench holding a 1 kHz tone 2.9 dB down, the added distortion is about 0.01 % THD — inaudible, and orders of magnitude below what clipping the same peak would produce. A hard ceiling sits behind the limiter regardless of this setting, and when it has to act it is counted rather than hidden.
Where the ceiling sits, in decibels below full scale. -3 leaves a little headroom and is the sensible default: it catches genuine peaks and leaves everything else alone. -6 is a firm limit for a delicate speaker run or an amplifier you know is undersized. Below about −12 the limiter starts squashing normal speech rather than protecting against peaks; if you need that much, turn the amplifier down instead. The diagnostics report the worst reduction actually applied since the last check, so you can tell a threshold doing its job occasionally from one fighting the material all day.
How long the limiter takes to let go once the loud passage has passed. Short values (under about 50 ms) make the output sound louder and busier and can pump audibly between words; long values (over about 400 ms) sound smooth but leave the whole announcement quieter after a single bang. 120 suits speech and music alike, and this is the one control in this section worth leaving alone until something specifically bothers you about how the system sounds.
The Pronunciation Workbench — the device’s own /pronunciations page — lists every unique word this system can say, marks the ones the neural voice is only guessing at, and lets you correct them or teach them by voice. Most of those words come from the schedule (TextData, 20) and the announcement templates, but plenty of announcements are typed on the spot: a page from the dashboard, a message from the phone app, a line over MQTT. With this True the words of those ad-hoc announcements are remembered too, so a name you keep having to announce turns up in the list instead of staying invisible. Words only, held in memory, capped at a few thousand and evicted oldest-first — never the sentences, never the audio, nothing written to disk. Set it False to list only what is in the configuration file.
In the Workbench you can say a word into your phone or laptop and have the device work out how to pronounce it. Your recording is never played on air — it is used only as a target: Multilarm measures it, searches for pronunciations that sound like it, then synthesises the best ones in the Kokoro voice and ranks them against your recording. You pick the one that sounds right and it is saved as an ordinary dictionary entry, so plurals and possessives of that word follow automatically. This setting is how many readings the Workbench offers you to choose from. It is not a speed dial, whatever earlier versions of this page said: measured on a Raspberry Pi 400, a derive takes about the same time at 2 as at 10 (30.7 s against 30.4 s for the same word), because the device always works up a shortlist of eight and this setting only decides how many of them you are shown. Lowering it will not make a slow Pi faster — it will only give you fewer readings to pick from. Raise it above 8 for an awkward name none of the first few gets right — the device genuinely does work out the extra candidates, and on a long word each one adds about 3½ seconds. On a short word it costs nothing and changes nothing: only a handful of sensible readings exist and you are already shown all of them.
The short recordings made in the Workbench — one word at a time, a second or two each — are kept on the device so it can work out how to say that word. They are training material, never announcement audio, and are never played through the speakers. With this True the cloud dashboard and the Android app can list those recordings, delete them, and send a new one for a word, which is what lets you teach a word from your phone while standing in the hall rather than having to be on the device’s own network. Set it False and the device refuses those three commands with a plain explanation; the Workbench on the local network is unaffected, and so are the saved pronunciations themselves, which are dictionary text either way.
Define named scenarios (e.g. Lockdown, Evacuate) — each with its own looped audio and relay channels — in a scenarios.json beside the device config. The built-in Emergency scenario always exists and reproduces the standard chain exactly. Fire one from the cloud dashboard’s Multilarm Box card (owner-only, obeys RemoteEmergencyAllowed) or on the LAN via POST /api/scenario/fire. The optional cap block (off by default) polls a Common Alerting Protocol feed (national weather/government/IPAWS) and auto-fires the mapped scenario when a real alert at/above your chosen severity arrives, clearing it on cancellation. Multilarm only ever fires your own local pre-defined scenario — never anything the feed links to; polling is outbound-only and size-capped.
Ready-made feeds (both checked against the live services 17 August 2026, neither needs an account or API key):
United States — https://api.weather.gov/alerts/active.atom?area=TX (swap TX for your state code). Open US-government data.
UK & Europe — https://feeds.meteoalarm.org/feeds/meteoalarm-legacy-atom-united-kingdom (swap the country). Aggregates 38 national meteorological services.
MeteoAlarm requires attribution: its data is CC BY 4.0, so wherever you display these alerts you must credit it — e.g. “Weather warnings © MeteoAlarm (meteoalarm.org), CC BY 4.0”. That is a licence condition. The NWS feed has none. Any other CAP 1.2 or Atom-wrapped feed also works — these two are simply the ones we test.
Command-line Arguments
Multilarm accepts these CLI switches: --config picks the XML settings file, --hub turns on the multi-instance Hub dashboard, --claim links the device to the cloud with a short setup code, --cloud-token writes a Cloud Relay device token into the config and exits, --setup / --no-setup control the first-run wizard, --diagnose runs the built-in diagnostics battery and exits, and --help / --version print and exit. A further set of scripting verbs drives an already-running device or measures an audio file — see Scripting verbs.
--config — alternate XML settings file
Multilarm.exe --config <path>
Multilarm.exe -c <path>
Multilarm.exe --config=<path>- Relative paths resolve against the application root (the folder containing
Multilarm.exe). - If the parent directory of the path does not exist, Multilarm creates it automatically.
- With no
--config, Multilarm loads the defaultMultilarm.config.xmlfrom the application root. - When a non-default config is loaded, the console title becomes
Multilarm <version> [<config-filename>]so you can tell instances apart at a glance. - The chosen file is what the hot-reload watcher follows, what live config POSTs from the Web Remote write to, and what AlternateConfig evaluates against at midnight.
--hub — start in Multilarm Hub mode
Multilarm.exe --hub
Multilarm.exe -H
Multilarm.exe --config zones\livingroom.xml --hub- Promotes this instance to hub at startup — the Web Remote serves an additional
/hubroute with a fan-out dashboard (instance grid, per-peer Skip / Test Alarm / Test Radio / Volume / Active-Config) for every Multilarm process registered under%LOCALAPPDATA%\Multilarm\instances. - Equivalent to pressing Ctrl+H after launch — useful when the hub instance is started by a Windows shortcut, scheduled task or systemd service that has no interactive console to receive a keystroke.
- Combine freely with
--config: the hub is just one of many instances on the host and is itself controlled through the same/hubdashboard. - Step the instance back down at runtime with Ctrl+Shift+H —
/hubreturns 404 again and reverse-proxy routes stop, but the rest of the instance keeps running unchanged. -His the short form (case-sensitive);--hubis case-insensitive.
--cloud-token — set the Cloud Relay device token and exit
Multilarm.exe --cloud-token <64-char-hex-token>
Multilarm.exe --cloud-token=<64-char-hex-token>
Multilarm.exe --cloud-token clear
Multilarm.exe --config zones\livingroom.xml --cloud-token <token>- Writes
CloudDeviceToken(field 53) into the config file and exits immediately — no audio is initialised, no Web Remote or relay is started. Passclearinstead of a token to disable Cloud Relay. - Safe to run while another Multilarm instance is live on the same config: the running instance's hot-reload watcher picks the change up within ~2 seconds and connects (or disconnects) the relay without a restart — ideal for headless installs, e.g. over SSH on a Raspberry Pi running Multilarm as a service.
- The token is validated (64 hex characters) before anything is written; an invalid value exits non-zero with no change. If the config file doesn't exist yet, it's created with defaults plus the token — handy for scripted first-time provisioning.
- Combine with
--config/--data-dirso the write targets the same file a normal launch with those flags would use. The interactive equivalent at a running console is Ctrl+K.
--claim — link with a setup code (no token to copy)
Multilarm.exe --claim
Multilarm.exe --config zones\livingroom.xml --claim- Shows a short code (e.g.
ABC-123) plusmultilarm.com/setup, then waits while you enter that code in the dashboard (My Devices → Enter code). When you do, the granted token is written into the config and the command exits. Ctrl+C cancels. - The easiest way to link a device — nothing to copy from the dashboard. Honours
--config/--data-direxactly like--cloud-token, and creates the config from defaults if it doesn't exist. Refuses if the device is already linked (clear it first with--cloud-token clear). - The interactive equivalent at a running console is Ctrl+K → Claim online.
--diagnose — run the diagnostics check-up battery and exit
Multilarm.exe --diagnose
Multilarm.exe --diagnose --json
Multilarm.exe --diagnose --section audio
Multilarm.exe --config zones\livingroom.xml --diagnose- Runs the same ~30-check silent battery as the device's
/diagnosticspage (deployment, clock & schedule, audio content, cloud/network, hardware) and prints each result as PASS / WARN / FAIL / SKIP with a fix hint on every problem. - The exit code is the number of failed checks — zero means all green — so install scripts and deploy pipelines can gate on it.
- Add
--jsonfor a machine-readable report, or--section <name>to run one section only. - If a Multilarm instance is already running on the same config, the command automatically tests the live instance through its Web Remote instead of starting a second engine — safe to run over SSH on a production device.
- Where it does run as a second process, checks that need exclusive hardware report a WARN, not a FAIL. A USB relay board on a serial port can only be opened by one program at a time, so a check running alongside the live service cannot reach it; the result says so and points at the running instance (
/api/hardware/statusor/api/diagnostics/run). A board that is genuinely absent still fails, and the operating system’s own reason for the failed open is always quoted — so a wrong port name never looks like dead hardware.
--setup / --no-setup — first-run wizard
- On a fresh interactive launch with no config, Multilarm runs a short setup wizard (name → use-case preset → voice → a few common settings such as volume, bell/signal times and zones → optional cloud link).
--setupforces it even if a config exists;--no-setupsuppresses the auto-run so scripted first launches just write plain defaults. - The wizard never runs under
--service, on a headless host, or when input is redirected.
--help / --version
Multilarm.exe --help (or -h, /?)
Multilarm.exe --version (or -v)Print the help text or the build version (1.<yyyy>.<Mdd>.<Hmm>) and exit immediately — no audio is initialised and no config is read.
Zone-based multi-instance deployments
The --config switch is the building block for running two or more Multilarm instances simultaneously on the same machine — each driving a different zone (room/speaker/playback device). Each zone needs its own config file with distinct settings:
AudioDevice (Playback) (24) | Different output device per zone |
MirrorDevices (25) | Optional: fan each zone out to multiple speakers |
AudioDevice (Recording) (26) | If Voice Broadcast / TTS recording is used per zone |
WebRemotePort (46) | Distinct port per zone (HTTP servers cannot share a port) |
CloudDeviceToken (49) | Each zone shows up as its own device in the Cloud Dashboard |
"C:\Program Files\Multilarm\Multilarm.exe" --config zones\livingroom.xml --hub
"C:\Program Files\Multilarm\Multilarm.exe" --config zones\bedroom.xml
"C:\Program Files\Multilarm\Multilarm.exe" --config zones\kitchen.xml--hub to one of the shortcuts (the living-room instance above) makes that process the Hub: open http://<host>:<port>/hub on its Web Remote port to control all three from a single page.Scripting verbs
Config templates (multi-site): in the cloud dashboard, an account owner can save a partial set of settings under a name and push it to as many as 64 sites at once. Partial is the point: the device merges the named settings into its live configuration and leaves everything else alone, so forty sites can take the same fade time or bell schedule without any of them losing their own audio folders, hardware settings or local timings. Build a template by loading a real device’s saved configuration and deleting the lines you do not want — picking from a real device is the only way to be certain a setting name is spelt the way the program spells it. Identity settings (device name, room name, cast name) and the cloud pairing token are refused outright, so no push can rename a fleet; passwords are encrypted at rest and never returned to the browser; and settings that are normally per-site (audio output, ports, emergency GPIO pin, multi-room role) are accepted but flagged before the push, because a wrong audio device does not raise an error — it silently plays nothing. The confirmation names the settings and the number of sites, offline sites pick the change up when they come back, and the Recent pushes list shows what each device itself reported — how many settings it recognised, or that it refused the change.
Endpoint supervision, the nightly self-test and the PA Health Report: a relay board whose USB adapter has been unplugged still “rings” the bell — the schedule fires, the log records it, and no metal moves. Every failure covered here has that shape, and each one stays invisible until the day it matters. Once a night Multilarm checks the output device, free space, every configured audio path, the speech engine, the relay board and every room following this device; anything that fails is raised as a fault, and faults already travel out over e-mail, Telegram and webhooks. The test is silent — the relay check re-asserts each channel to the state it is already in, which is a genuine end-to-end serial write that changes no contacts and never pulses the bell — so it can safely run at three in the morning. An optional amplifier loopback plays a short tone and listens for it returning on a capture input wired from the speaker line, passing only when that exact frequency comes back well above the room’s own level; because it makes a sound it is off by default, and when it cannot run it records “not run” rather than “passed”. Once a week the runs are rendered into a printable PA Health Report, written beside the config and served at /api/supervision/report — a dated record of the system proving itself, which is what a fire officer, an insurer or a facilities manager can actually use. Supervision can only observe: there is no stop, no volume, no schedule change and no relay actuation anywhere in it.
Timers, break reminders and daily routines: all of this was already possible with the scheduler, in the vocabulary of prayer times and time-range rule strings — which is exactly why nobody found it. A timer is a one-shot countdown somebody starts by hand (POST /api/timers/start with a label and a number of minutes); with nothing else supplied it announces “Exam finished.” when it runs out. A routine recurs, either at a time of day or every so many minutes inside a window, with an optional day list. Interval routines are anchored to the start of their window rather than to boot time, so “every 90 minutes from nine” lands on the same minutes every day and a restart does not shift the day. Ready-made presets ship with it — break reminders, hourly stand-up, a 25-minute focus block, wake, lunch, end of the working day, wind-down, lights out — so the usual case is picking one and changing the time. Running timers survive a reboot; a timer that elapsed while the machine was off is discarded rather than fired, because a burst of yesterday’s timers during Monday assembly is worse than losing a countdown. A routine can only start audio and always plays at priority 3 (queued): a reminder is not urgent, so it waits for whatever is already playing, and it can never displace an announcement, an alarm or an emergency.
Phrase packs — announcements in any language: the built-in neural voice speaks English only, and we will not claim otherwise; synthesising a language badly is a safety problem when the sentence is an evacuation instruction, not a cosmetic one. A phrase pack is the honest answer: a single .mlpack file of pre-recorded audio, spoken by somebody who actually speaks the language, with a manifest saying what each recording means and an English gloss so an operator who does not read the language can still pick the right one. It is a plain zip — hand it over on a USB stick, e-mail it, or pass it to another site; no account, no download service and no internet involved. Build one with ops\make-phrase-pack.ps1, install it from the Web Remote or by copying the folder into <config folder>\PhrasePacks\. Play one or several at POST /api/phrasepacks/play — a list, because a real evacuation announcement is the same instruction in two or three languages one after another — at priority 1 (immediately) or 3 (queued) and nothing else, exactly as for speech. A phrase can only start audio; there is no stop, no volume and no silence action, because the person who recorded a pack is not the person who commissioned the building. Installed recordings are ordinary files at a known path, so scenes, alarm folders and the External Trigger API’s play-file work with them unchanged. An untrusted archive is checked whole: entry names are validated, the pack is staged and only made visible once complete, and one missing recording refuses the pack outright rather than installing part of it.
Sound masking / focus audio: generated masking noise on a schedule — pink, brown, white, or hush (pink with the hiss filtered off) for a clinic waiting room. The noise is computed on the device from a noise algorithm rather than played from a sample library, so nothing is licensed, nothing is downloaded and the whole feature adds a two-minute file rendered once into the config folder. The level is capped at 0.6 deliberately: masking belongs under the conversation it covers, and a level of 1.0 is a fault, not a setting. The radio always wins — masking starts only when the background channel is genuinely idle and never stops anything, so a site that schedules both simply hears its music; the status carries radioHasChannel so an operator can tell “not scheduled” from “the radio has the channel” instead of reporting a fault. Alarms, announcements and emergencies interrupt masking through the ordinary priority rules, with no special case. Settings live in <config name>.masking.json, read and written at GET/POST /api/masking.
Chime and tone library: twelve chimes and signal tones — two- and three-note chimes, soft and bright bells, marimba, glass, a low gong, pips, a double alert, a school bell and an end-of-break tone — generated into a Chimes folder beside the configuration on first run, ready to point TTSChimePath or an alarm folder at. Every competitor ships a chime set and we used to ask people to find their own files; what we deliberately did not do is bundle a “royalty-free” sample pack, because those carry redistribution terms a customer installing an MSI is never shown and cannot re-audit. These are synthesised from sine waves and decay envelopes, so there is no third party in them at all and the installer grows by megabytes rather than tens of megabytes. An existing file is never overwritten — replace one with your own recording and it stays — and deleting one re-renders it on the next start. GET /api/chimes lists the set.
Live calendar sync: the Config Generator’s .ics file import is unchanged and still owns the schedule — it turns a term calendar into rules at design time, which is the right tool for dates settled months ahead. Live calendar sync adds the other half: the device subscribes to one or more calendar addresses, re-reads them every fifteen minutes, and announces events as they come round, including one added this morning. Any private .ics subscription address works — Google Calendar’s secret address in iCal format, Outlook’s publish a calendar link, or a CalDAV collection such as Nextcloud or Radicale with a username and password. There is deliberately no Google or Microsoft sign-in: a subscription link carries the calendar and nothing else, needs no account with us, and the customer revokes it in one click, which is a better trade for a system whose point is that nothing has to leave the building. Each feed can announce a set number of minutes ahead, filter by words in the event title, skip all-day entries and stay silent during quiet hours, with the spoken text built from {summary}, {time}, {location} and {lead}; a feed can run a scene instead of speaking. A calendar can only start things — there is no stop, no volume and no schedule-disable action, because an event titled “quiet please” must never be able to silence a building — and announcements are queued behind whatever is playing, so the diary can never cut across an emergency broadcast. Feeds are stored in <config name>.calendars.json and managed over the LAN API at GET/POST /api/calendars, with POST /api/calendars/refresh to fetch every feed at once and report what each one returned.
Node-RED nodes: if you already run Node-RED, Integrations\node-red adds three nodes — speak, scene and status — that talk to the device’s Web Remote API directly on your LAN (no cloud account, no broker, nothing leaves the building). Copy the folder to the Node-RED machine and npm install it from disk; the device host, port and Web Remote credentials go in a config node, so they live in Node-RED’s encrypted credential store rather than in a flow file people paste into forums. The scene node’s dropdown reads the live scene list off the device, and every node raises a catchable error — including the case where the device answers HTTP 200 with an error body, so a flow can never log “announced” for an announcement that never played. There is no stop, volume or clear-emergency node, on purpose: a flow runs with nobody watching, and starting audio from an automation is recoverable where silencing a live building is not. An example flow (webhook → announcement, 502 with the device’s own message on failure) ships in examples/.
These make Multilarm drivable from a shell script, cron, Task Scheduler, a Home Assistant shell_command, Node-RED or an SSH session. Audio is owned by the running instance, so each verb talks to that instance over loopback using the port and credentials from the resolved config — the device must already be running, and it is safe to call against a live site.
multilarm --say "The hall closes in ten minutes"
multilarm --scene closing
multilarm --stop-scene
multilarm --list-scenes
multilarm --list-packs
multilarm --apply-pack retailThis one measures a multi-room group. It joins as a silent observer — it deliberately plays nothing — and prints one line of JSON: the clock offset between the two devices, the best round trip, the spread in chunk arrival, how many chunks arrived after their play moment at the current buffer, and roomToRoomBoundUs, the honest bound on how far apart two rooms can be. With no address it finds the sending device itself.
multilarm --rooms-probe
multilarm --rooms-probe 192.168.1.50:7451 30These read a file instead, and need no running device:
multilarm --analyse recording.wav
multilarm --detect-alarm clip.wav
multilarm --normalise ./sounds--analysereports peak, RMS, an approximate A-weighted level, crest factor, whether the file clips, and the gain needed to reach a −20 dBFS target. 16-bit PCM WAV.--normalisewrites<name>.normalised.wavbeside each file and never modifies your originals. Gain is reduced if it would clip — the peak wins over the loudness target, so normalising can never distort a file — and silent files are skipped rather than amplified.--detect-alarmlooks for the standard smoke-alarm sound (the ISO 8201 / NFPA 72 three-beep pattern). It requires both the right pitch and the right rhythm, so a continuous buzzer does not match.- Exit codes, for scripting: 0 success, 1 argument error, 2 could not reach the device, 3 the device refused.
The task-based console
Alongside the classic dashboard at / and the config editor at /config — both unchanged and fully supported — there is a second console at /app, organised around what you want to do rather than how the software is built.
- Now — what is playing, what is next, and a box to announce something immediately.
- Scenes — the one-tap grid, a picker for a ready-made starter set, and a full editor.
- Automations — When / If / Then rules in plain English.
- Schedule — a visual table and the raw text, side by side. Both edit the same setting; the text view is never taken away, and anything the visual editor cannot represent is preserved exactly as written.
- Settings — every setting, generated from the program itself, with per-field help, a Basic/All toggle, and a badge on anything needing a restart.
Scenes, packs and automations
A scene is a named list of steps run in order — play, say, wait, volume, relay, stop. Scenes live in <config name>.scenes.json beside the config, because nothing in the config file can express “play this, then say that, then ring the bell”. Your schedule and every existing feature are untouched; a site with no scenes file behaves exactly as before.
Six use-case packs — Home, Shop or cafe, Gym or studio, Office or workshop, School, Place of worship — seed a starter set. A pack is purely additive: it never replaces a scene you already have, never touches any other setting, and applying it twice adds nothing the second time. The Place of worship pack adds hall announcements only and leaves a prayer-time schedule exactly as it is.
Automations bind a trigger to an action: when a smoke alarm is heard, the room is louder or quieter than a level you choose, the clock reaches a time, or Multilarm starts → then run a scene or announce text, with optional quiet hours and a minimum wait between firings. Rules live in <config name>.automations.json.
An automation can only start things. There is deliberately no rule that stops audio, mutes the device or disables the schedule, so no rule — however it was written or edited — can be the reason a building goes quiet.
Listening to the room
Switching on Listen to the room (ListenEnabled) lets the device measure the room every twenty seconds and recognise the standard smoke-alarm pattern. Either can be used as the when of an automation. With Match announcements to the room (AdaptiveGainEnabled) a scene also raises its volume in a noisy room and lowers it in a quiet one, restoring your volume afterwards.
What happens to the audio. Listening is off until you turn it on. A short clip is written to one temporary file, measured, and deleted immediately — before it is analysed, so an interruption leaves nothing behind. There is no rolling buffer and no archive. Only a level and an alarm/no-alarm label leave the module: no audio is stored, transmitted, or sent to the cloud. Every detection is written to the audit log, and GET /api/listen/status reports "audioRetained": false, so this is machine-checkable rather than a promise in a document.
Listening always yields the microphone. If push-to-talk, a voice broadcast or speech recording is active it skips that turn entirely, so it can never be the reason an operator cannot reach the microphone.
Adaptive gain applies to scenes only. It cannot make a scheduled alarm or an emergency announcement quieter, and it is clamped so it never reaches silence.
Installing the cloud console on a phone or desktop
The cloud console can be installed like an app — its own icon, its own window, no address bar — on iPhone and iPad, Android, Windows, macOS and Linux. It is the same console, so there is nothing new to learn and nothing extra to keep updated. On Android and desktop an Install app button appears in the top bar when the browser supports it; on iOS use Safari's Share → Add to Home Screen. Step-by-step instructions for each platform live at /cloud/app/.
Installing does not make the console work offline, and that is on purpose. Without a connection you get a page that says so. A control screen that shows the last state it happened to remember is worse than one that admits it does not know — you would act on a device list that might be hours old. Nothing about your devices is cached: no schedules, no status, no audio.
Your devices never depend on it. Every schedule, alarm and announcement runs on the device itself. Losing the internet, this app, or the cloud entirely loses the remote view of a building — never the building's audio. On site you do not need it at all: each device serves its own Web Remote on the local network.
Talkback: calling the office from the building
Push-to-talk sends the office's voice into the building. Talkback is the same channel with the arrows reversed: somebody standing at the device rings the operator, and the operator can answer and hear the room. A caretaker at the panel, a teacher at the front desk, a warden during a drill — people who need to reach whoever is watching the dashboard, without a phone in hand.
A call can only ever be started at the device. There are two ways: the device's own /talkback page on the local network, or Ctrl+W at the console. The cloud dashboard can answer a call, decline it, listen while it is live and hang up — and nothing else. No command exists that opens a microphone in a building from outside it. That absence is the feature: a remote listening switch that can be flipped without anybody in the room knowing is a surveillance tool, and this is not one.
What the room can tell. The device plays an audible chime when a call is answered, so nobody is listened to silently. The call rings for at most sixty seconds unanswered, runs for at most five minutes once live, and ends by itself if the listener's browser goes away. Audio is buffered for a few seconds at a time and swept the moment the call ends — nothing is recorded and nothing is stored, on the device or in the cloud. Every request, answer, decline and hang-up is written to the audit log.
One microphone. Talkback shares the device's single input with everything else that needs it, in a fixed order: push-to-talk, then talkback, then voice-broadcast recording, then recording, then room listening. A live PA announcement wins over a call; a call wins over passive listening. If the microphone is busy with something above it, answering is refused with the reason rather than failing quietly.
Device API
The device serves a local HTTP API on the same port as the console. A machine-readable OpenAPI 3.1 description is published at /api/multilarm-openapi.json, generated from the device's own route table so it cannot drift from what the software actually serves.
Endpoints added alongside the new console:
GET /api/config/schema— every setting described: label, help, group, type, range, whether it needs a restart.GET/POST /api/scenes,GET /api/scenes/status,POST /api/scenes/run,POST /api/scenes/stopGET /api/packs,POST /api/packs/applyGET/POST /api/automationsGET /api/listen/statusGET /talkback,GET /api/talkback/status,POST /api/talkback/request·answer·decline·hangup·keepalive,GET /api/talkback/chunk— see Talkback
When console credentials are set, every endpoint uses HTTP Basic auth. When they are blank the console binds to loopback only.
Console Key Commands
| Shortcut | Action |
|---|---|
| Ctrl + A | Test-play AmbienceFile for AmbienceDuration milliseconds |
| Ctrl + B | Enter Voice Broadcast mode — R record/stop, P preview, T transmit (Y/N confirm) through the playback device, D discard, Ctrl+M exit |
| Ctrl + D | Dump the full console log buffer (up to 500 timestamped entries) |
| Ctrl + F | Test-play a random radio file for 10 seconds |
| Ctrl + G | Relay board bring-up test (Multilarm Box) — pulses the bell and zone-mute channels, holds the emergency LED for a second, then prints every channel state. Use it to confirm RelayProtocol (A0 vs FF) before setting RelayPort on a production config |
| Ctrl + H (or Backspace) | Promote this instance to Multilarm Hub — enables /hub dashboard and reverse-proxy fan-out to every peer instance registered under %LOCALAPPDATA%\Multilarm\instances. Many Windows terminals deliver Ctrl+H as ASCII BS, so Backspace on its own toggles the same promotion as a fallback. Green log line "Multilarm Hub enabled — http://localhost:<port>/hub" confirms the keystroke was accepted. No-op if already in hub mode |
| Ctrl + Shift + H (or Shift+Backspace) | Step this instance down from hub mode — /hub returns 404 again and the reverse-proxy routes stop. The instance keeps running its own alarms, radio, cloud relay etc. unchanged |
| Ctrl + I | Show runtime status — uptime, current audio, radio state, volume, crossfade, volume profile, active config, web remote, hub state + peer count, cloud relay and next alarm info |
| Ctrl + L | List audio files played in the past hour (buffer clears at each hour) |
| Ctrl + N | Skip: advance to the next track when in folder mode; tear down and reconnect the stream when in RadioStreamURL mode |
| Ctrl + O | List audio devices — playback and recording tables with indices, names and [default] flags. Use the printed indices when choosing values for PlaybackDevice, RecordDevice and MirrorDevices |
| Ctrl + R | Open TTS recording interface — record unique words from TextData and save to TTSPath |
| Ctrl + S | Test-play current console text using the TTS word library |
| Ctrl + T | Test-play a random alarm audio from a random AlarmPath folder |
| Ctrl + X | Exit Multilarm |
Use the Print button in the footer to get a quick-reference printout of these shortcuts.
Tips & Tricks
- Hard to read this site in bright light? Use the Light / Dark button in the bottom-right corner of any page to switch themes. Your choice is remembered on this device. The same toggle is on the Cloud dashboard, the Configuration Generator, and the device's own Web Remote pages (dashboard, config editor and hub).
- Looking for something? Use Search — the button in the bottom-right of any page, the Search link in the top navigation, or just press /. It searches every page on the site (titles, headings and page text) and works offline.
- When preparing timetable data (e.g. a full Salat calendar), use a text editor or Microsoft Word to clean up spaces, characters and line feeds before pasting into config. Use find/replace with special character codes — e.g.
^pfor paragraph marks in Word — to batch-format entries efficiently. - On Linux/Raspberry Pi, configure Multilarm as a systemd service to auto-start headlessly at boot. Once set up correctly, no further interaction with the device is needed.
- When recording TTS word files with Ctrl+R, allow roughly 250 ms of silence after each word for natural-sounding playback.
- To cover all time-related TTS, record audio for numbers 0–20, 30, 40 and 50 — 24 files in total.
- Use folder tags in file and folder path settings (AmbienceFile, AlarmPath, TTSPath) for automatic cross-platform path resolution. Each tag is replaced at runtime with the platform-appropriate directory:
For example,{app}App install directory — Windows: ...\AppData\Local\MultilarmLinux:~/.local/bin{temp}System temp — Windows: ...\AppData\Local\TempLinux:/tmp{home}User profile — Windows: C:\Users\NameLinux:/home/name{docs}Documents — Windows: C:\Users\Name\DocumentsLinux:/home/name{data}App config — Windows: ...\AppData\RoamingLinux:~/.config{local}Local data — Windows: ...\AppData\LocalLinux:~/.local/share{app}\Adhan\Ambience.mp3resolves to~/.local/bin/Adhan/Ambience.mp3on Linux and...\AppData\Local\Multilarm\Adhan\Ambience.mp3on Windows. The Configuration Generator provides clickable tag insert buttons next to all path fields. - Use a 29-day February when building full-year data, and verify UK daylight savings adjustments are correctly applied after the end of March and October.
- Use the Multilarm Configuration Generator to load, edit and save
Multilarm.config.xmlwithout hand-editing raw XML. - When reporting bugs, always include both
Multilarm.error.logandMultilarm.config.xmlfrom the application root. Reports without both files cannot be effectively diagnosed. - Sample configurations demonstrating Multilarm in a daily (Care Home PA, and Home two-PC), weekly (School PA) and monthly (Gymnasium PA) routine are listed in the Samples section of the Download Centre — CareHomePA-Daily, SchoolPA-Weekly, GymnasiumPA-Monthly and HomeTwoPC-Daily (a home setup driven from a second machine over the Web Remote, with an audio sequence, a TTS chime and quiet-hours volume rules). Copy
Multilarm.config.xmlfrom the relevant subfolder into the program root directory along with any associated audio folders. Use the{app}folder tag in paths for automatic cross-platform resolution. - An alternative config pre-loaded with Bangladesh prayer times is available from the Configurations section of the Download Centre.
- Config hot-reload watches
Multilarm.config.xmlfor changes — edit and save the file while Multilarm is running and updated settings are applied automatically without a restart. - Enable the Web Remote by setting
WebRemoteEnabledtoTrueand choosing a port (default 6580). Openhttp://<machine-ip>:6580/on your phone or any browser on the same network. Multilarm automatically creates a firewall rule on startup — if running as administrator (Windows) or root (Linux), no manual firewall configuration is needed. If running without elevation and other devices cannot connect, run Multilarm as administrator once, or add the rule manually:netsh advfirewall firewall add rule name="Multilarm Web Remote" dir=in action=allow protocol=tcp localport=6580 - The Web Remote dashboard also lets you edit configuration live — change any setting from the browser and click Save & Reload. Changes are written to
Multilarm.config.xmland applied at runtime immediately. - Use Ctrl+N to skip the current radio track if you don't like it. The next track in the shuffle plays immediately. You can also skip remotely via the Web Remote API:
POST /api/skip. - Use Ctrl+F to preview a random radio file for 10 seconds without affecting the main radio shuffle. Useful for checking that your radio folder is configured correctly.
- Alarms (Adhan) always take highest priority over all other audio — radio, quotes, ambient sound and TTS. When an alarm fires, background audio fades out gracefully and resumes seamlessly after the alarm finishes. No manual timing adjustments are needed.
- Use Alarm Repeat to play the same Adhan file multiple times per trigger. Set
AlarmRepeatCountto the number of plays andAlarmRepeatGapto the silence gap between repetitions. The whole sequence is one alarm event — radio and ambient remain suppressed for the full duration. - To play several different files for one alarm, write it into the path rather than adding a list. In
AlarmPath, join sources with a space-padded+:{app}\Adhan\Bleep\ding.mp3 + {app}\Adhanplays the bleep, then a random adhan, then the spoken announcement — one uninterrupted event. Add a mode to a folder to change how many files it contributes:>all(every file, filename order),>shuffle(every file, random order),>seq(one per day, stepping through and remembering where it got to), and*Nto cap the count (>shuffle*2).TTSChimePathaccepts exactly the same thing, so{app}\Adhan\Bleep>allgives you a multi-tone chime. UseSequenceGapMsfor the silence between the files andSequenceMaxSecondsas a safety cap. A plain folder path keeps picking one file at random, so nothing changes until you ask for it. Watch it in the user guide (32:05) if you would rather see it done. - Volume Profile rules follow the same syntax as
RadioScheduleRulesbut accept an extravolume=<0.0-1.0>filter (e.g.22:00-07:00,volume=0.3;). When a rule is active its volume overrides the masterVolumesetting; when no rule is active the master volume is used. - Voice Broadcast (Ctrl+B or the Web Remote card) lets you record a short clip from the record device, preview it locally, and — after a Y/N (console) or browser confirm (web) prompt — transmit it through the playback device at alarm priority. Useful for one-off PA announcements. The Web Remote
POST /api/voice/transmitendpoint additionally requires a{"confirm":true}body and returns HTTP 400 otherwise. - AlternateConfig switches config files on a date schedule. Set it to a pipe-delimited list of
filename,rulepairs — the rule uses the same grammar asRadioScheduleRules(a time range plus optionalm=/d=/w=/nw=/ldfilters). For an “all-day” switch use the 24h sentinel00:00-00:00. Example:Ramadan.config.xml,00:00-00:00,m=3|Summer.config.xml,00:00-00:00,m=6-8. The first matching rule at midnight wins; filenames may use the same{app},{data}, etc. tags as other path settings. - Enable Cloud Relay to control Multilarm from anywhere in the world — no port forwarding needed. First get a Cloud account (set up personally — that page explains), then log in to the dashboard and add a device to get a 64-character token. Paste the token into
CloudDeviceToken— the relay is hardcoded tohttps://multilarm.com/cloudand activates automatically whenever the token is set. Multilarm connects outbound via HTTPS. - Cloud Relay and local Web Remote can run simultaneously. Enable both for fast local control (Web Remote) and internet control (Cloud Relay) on the same instance.
- If Multilarm goes offline temporarily (power outage, reboot), any cloud commands sent during that time expire after 60 seconds. The cloud dashboard shows the device as OFFLINE within 30 seconds.
- Keep your
CloudDeviceTokensecret. If compromised, remove the device from the cloud dashboard and add a new one to generate a fresh token.
Android App
The Multilarm Android app puts the whole cloud dashboard on your phone, redesigned for touch: large, clearly labelled buttons and big text that scales with your system font size. Sign in with the same account you use on the cloud dashboard — admins get the full toolset, operators get just the day-to-day controls on the devices shared with them.
What you can do: see live status and the next alarm; Skip, Test Alarm, Test Radio and set Volume; view the upcoming Schedule; Speak Text aloud on the device; record a Voice Broadcast on your phone's microphone (or upload an audio file), preview it, then transmit it through the device's speakers — so it works even when the device itself has no mic; manage Audio Files; and go live on the PA with Live PA (your phone's mic streams straight to the device's speakers). Owners additionally get the full Configuration editor, TTS word-library fill, External Triggers, Batch actions, Email alerts, Operator management, the Audit log, and adding, renaming, removing and revealing the pairing token of devices.
Push notifications: get a notification on your phone within seconds when something goes wrong — a device goes offline, an alarm is missed, an audio file is missing, the disk runs low, or the speaker has a problem. Turn it on under Email alerts → Phone notifications (owners): tick which events should push, switch on Notify this phone, allow notifications when prompted, and use Send test notification to confirm. Push works even when the app is closed, and tapping a notification jumps straight to that device. It runs alongside email/webhook alerts — no need to choose. A lightweight offline check also runs in the background as a fallback on phones without Google Play services.
Telegram alerts (free): the same alerts can also go to a Telegram chat at no cost — no SMS provider needed. Under Email alerts → Telegram (owners), create a bot with @BotFather to get a bot token, message your new bot once, then read your numeric chat ID from @userinfobot. Paste both in, tick Send alerts to Telegram, and press Test Telegram. Add several chat IDs (comma-separated) to reach a team; group and channel IDs are negative. Telegram fires alongside email, webhook and phone push for any enabled event.
Visual display (wall/TV): turn any cheap TV, tablet or Raspberry Pi-with-monitor into a full-screen display for a device — a large clock, the next prayer or bell with a live countdown, the Hijri date (mosque mode), an optional scrolling notice, and an automatic full-screen emergency takeover when the device's emergency is active. Set it up under Dashboard → Display (owners): pick the device, choose Mosque / School / Factory mode and a theme, optionally add a notice ticker, then open the public link on the screen and bookmark it full-screen (kiosk). The link is read-only — it shows status but can never control the device — and can be rotated at any time to revoke old screens.
Digital signage you already own: if the building already runs signage — Xibo, Yodeck, ScreenCloud, Rise Vision, OptiSigns, or anything with an RSS or ticker widget — it can carry Multilarm with no second screen and no second player. The Dashboard → Display card shows a signage feed URL beside the display link (/cloud/api/signage.php?token=…). Paste it into the player’s RSS or ticker widget: an active emergency comes first, then your notice text, then a warning if the device has stopped reporting, then the next scheduled event. &format=json and &format=txt serve the same items for players that prefer them. It reuses the display’s existing read-only token — one public secret per screen, and Rotate link revokes the feed and the display together. Players that can render a web page do not need the feed at all: give them the display link and they get the full screen.
Slack, Microsoft Teams and Discord (free): alerts can also land in a chat channel the team already watches. Create an incoming webhook in your own workspace and paste the URL under Email alerts → Slack / Microsoft Teams / Discord (owners), tick Post alerts to a chat channel and press Test chat. Slack: Apps → Incoming Webhooks. Teams: the channel’s Workflows → Post to a channel when a webhook request is received, or a classic connector. Discord: Edit Channel → Integrations → New Webhook. Multilarm installs no app and holds no workspace token — only the URL, stored encrypted and never displayed again, because whoever holds it can post into your channel. The platform is taken from the URL, not a dropdown: a Teams endpoint accepts a Slack-shaped message with a success code and then renders nothing, which is the worst way for an alert channel to fail. Fires alongside email, webhook, push and Telegram for any enabled event.
Notify people (mass notification): alert a whole list of people at once across email, phone push and Telegram, with an “I’m safe” acknowledgement link so you can see who has responded. Under Dashboard → Notify People (owners): add recipients (email and/or Telegram chat ID, optional group tags), compose a message, pick the channels and send; a live board shows sent / failed / acknowledged counts. Email uses your Email Alerts SMTP settings, Telegram uses the bot token there, and push goes to your own registered phones — all three cost nothing.
SMS (optional, your own account): for people who will not install an app, a recipient can also carry a mobile number and be texted. Multilarm does not sell SMS credit — you open your own Twilio account and paste its Account SID, auth token and sender number into Email Alerts, so messages are billed to you directly at Twilio’s rate (around US$0.0075 each) and the account stays under your control. Numbers must be in international form (+447700900123), and because a text is billed per 160‑character segment the composer keeps emergency messages short. Leave the Twilio fields blank and SMS simply stays off — email, push and Telegram are unaffected.
Handy extras: stay signed in, optional fingerprint lock, and a full in-app help guide.
Multilarm Network
Multilarm Network watches the network your device sits on and tells you, in plain English, when something is wrong with it. It answers the question that wastes the most time when a site stops working: is this Multilarm's fault, the network's fault, or the internet provider's fault?
Until your device is paired with the cloud, it does nothing at all. With no pairing token the monitor simply sleeps: no scanning, no network traffic, no cloud calls. That is why it can be installed everywhere by default — on an unpaired machine it costs you an idle background process and nothing else.
What it does
- Finds every device on the network. It lists what is connected, with each device's address, manufacturer, network name where one is published, and a best guess at what kind of thing it is (camera, printer, phone, network gear and so on).
- Names manufacturers offline. Manufacturer names come from a copy of the official IEEE hardware registry built into the software — roughly 53,000 manufacturers. No lookup service is contacted, so naming works on a site with no internet and nothing about your equipment is sent anywhere to identify it.
- Tracks what is up and what is down, including a watch list of the devices you actually care about, so a missing till, camera or access point raises an alert rather than being lost in a long list.
- Runs periodic speed tests and compares the result against the speed you are paying for, so “the internet feels slow” becomes a number you can take to your provider.
- Diagnoses faults in plain language — for example that the internet is down but your own equipment is fine and the fault is with your provider, that the router itself has stopped responding, that a watched device has dropped off, that throughput is well below plan, or that a new device has appeared on the network.
Where you see it
In the cloud dashboard, under the device's Network view. Anything serious reaches you through the alerting you have already set up — email, Telegram and phone notifications — with no separate configuration.
Also from the dashboard you can turn monitoring off entirely, change how often it scans and speed-tests, set quiet hours so the speed test does not use bandwidth during your busiest period, enter the download and upload speeds your plan promises, and choose which devices go on the watch list.
What it will never do
- It only ever looks. It cannot change a setting on any device, block anything, or disconnect anything. There is no remote-control surface at all.
- It does not read your traffic. It does not capture, inspect or store the contents of anything on your network — only which devices are present and whether they answer.
- It runs without administrator privilege on Linux and the Raspberry Pi, and opens no port for anything to connect to.
- No AI is involved. Every verdict comes from a fixed, published set of rules, so the same situation always produces the same answer and nothing about your network is sent to any AI service.
- It can never interfere with an announcement. The monitor is a separate program from the audio engine, deliberately: a network scan that stalls cannot delay a prayer time, a bell or an emergency broadcast.
Turning it off
Switch monitoring off in the dashboard and the daemon stops scanning while staying installed — the usual choice. To stop the background service as well: on Windows, set the Multilarm Network service to Disabled in Services; on Linux or a Raspberry Pi, run systemctl --user disable --now multilarm-netmon (or sudo systemctl disable --now multilarm-netmon on an appliance-style install). The main Multilarm service is unaffected either way.
Incidents & drills
Sending one message to everybody is easy, and the Notify People card in the cloud dashboard still does exactly that, unchanged. An incident is the next step up: the plan you write once, calmly, and fire in one tap when there is no time to think. Find it at Incidents in the cloud dashboard's top bar.
What a template holds
- The message — subject line and body, written in advance instead of typed under pressure.
- An escalation ladder — who is told first, and which group is added after how many seconds if nobody has acknowledged yet. Wardens at once; duty managers two minutes later; everyone after five. Anyone who has already acknowledged is never contacted again.
- Which devices react — a scenario to play on the speakers, and a line of text to put on any connected display for as long as the incident runs. The display's previous message is put back when you close it.
- When to stop — how many acknowledgements end the escalation, whether to re-send the current stage on a timer, and how long to wait before closing the incident automatically.
Starting one
Three buttons sit next to every template. Start runs it for real. Drill runs the whole thing end to end but prefixes every message and every display line with DRILL — THIS IS A TEST, so you can rehearse without frightening anyone. Silent drill goes further: people are notified, but no speaker plays and no display changes — useful for testing the human chain during business hours. The same start is available to the Android app, so a phone in a pocket is a panic button.
While it runs, the Incidents page shows which stage it has reached and how many people have acknowledged. Acknowledging is one tap on a link in the message; no login is needed.
The after-action report
Every incident and every drill produces a printable report: when it started and who started it, every stage that fired, every person contacted on every channel, who acknowledged and when, what was played and where, your closing note, and a complete time-stamped ledger of everything that happened. It is the document an insurer, a licensing officer or a safety review asks for after the event, and a drill produces exactly the same evidence as the real thing. Reports are kept even if you later delete or rewrite the template — each incident keeps its own copy of the plan it ran.
Incidents need at least one notification recipient, so add people to the Notify People card first and give each of them a group tag (for example wardens, managers) — those tags are the rungs of the ladder.
Desktop alerts
Speakers reach people who can hear them. Not everyone can — a machine room, a call centre with headsets on, a deaf member of staff, a night shift with the volume down. Desktop alerts put the same message on every screen you choose to point at the device, and let whoever is sitting there say “seen it”.
Every Multilarm device publishes a small notice board of its own: what is happening right now, whether it is a drill, and whether an acknowledgement is wanted. Three things read it, and you can use any or all of them.
1. Any screen with a browser
Point a spare monitor, a signage player, a tablet or a kiosk browser at http://<device>:6580/alert. It sits quiet and dark until something happens, then fills the screen. No installed software, no cloud account, no internet — it talks only to the device on your own network, so it keeps working when the line to the outside world is down. If the alert asks for one, an Acknowledge button appears.
2. Windows — the Multilarm tray companion
The tray app already watching your instances now watches their alerts too. When one starts, it takes the screen over; when the device says it is over, the takeover disappears by itself. It never steals your keyboard, so a half-typed message survives. Under Settings you can turn the takeover off entirely, swap the full screen for a banner across the top (for a till or a control room that must stay usable), and choose whether a new alert plays a tone — off by default, because the building's own speakers are the alarm.
3. Linux — the alert agent
A small script, multilarm-alert-agent.sh, does the same job with whatever the machine already has: a kiosk browser if there is a desktop, a notification if there is not, and a message to every terminal on a headless box. Run it as a systemd --user service; it needs only sh and curl.
Where the alerts come from
- The device itself — press the emergency button, or trigger an emergency from the web panel, and every watching screen takes over at once. This path involves no cloud account whatsoever.
- A cloud incident — starting an incident or drill takes over the screens of every device on that incident, including a silent drill: silent means make no sound, not say nothing.
Acknowledging from a screen
An acknowledgement from a screen counts towards the incident's target exactly like a tap on the link in an email, and it appears in the after-action report under Acknowledged from a screen with the machine it came from. If the internet is down when somebody clicks, the device holds the acknowledgement and delivers it when the connection returns — it is queued, not lost.
A screen can only ever acknowledge. It cannot start, stop, silence or delay anything, which is why it needs no password and no permission: the worst a compromised monitor can do is claim that somebody read the message.
Bug Reporting
All handled and unhandled exceptions are automatically appended to Multilarm.error.log in the application root. The application must have write access to this directory.
Multilarm.error.log and Multilarm.config.xml when reporting a bug.Downloads
All binaries, installers, configuration presets, sample applications, Linux scripts, documentation and Cloud Relay dashboard links live in the dedicated Download Centre. Jump straight to the section you need:
Binaries
Windows x64
Binary + multilarm_audio.dll
Linux ARM 32-bit
Raspberry Pi (32-bit OS)
Linux ARM 64-bit
Raspberry Pi & ARM64 SBCs
Resource Files
Adhan, Bleep, Ambient, TTS (ZIP)
Installer
Configuration Files & Samples
Config Generator
Visual editor for Multilarm.config.xml
Default Config
UK Sheffield prayer times
Bangladesh Config
Bangladesh prayer times preset
Sample Applications
Care Home (daily), School (weekly) & Gymnasium (monthly) PA presets
Linux Scripts
Install, service, uninstall & Pi audio configs
Documentation PDF
Full offline reference manual
Cloud Relay Dashboard
Get an account
Cloud accounts are set up personally
Login
Sign in to your account
Dashboard
Manage devices & control Multilarm
Checking that a download is genuine
Multilarm is only ever distributed from multilarm.com, winget, and Chocolatey. A copy from anywhere else is not ours, whatever it is called.
Every release file is listed with its SHA-256 fingerprint in SHA256SUMS, which itself carries a digital signature (SHA256SUMS.sig) made with a key that is kept off the web server — so even someone who broke into the website could not publish matching fingerprints for a tampered file.
To check a file you have downloaded:
On Windows: certutil -hashfile Multilarm.exe SHA256
On Linux or a Raspberry Pi: sha256sum -c SHA256SUMS
If the fingerprint does not match the one published here, do not run the file — delete it and tell us at hello@multilarm.com.
Two-factor authentication on your Cloud account
Your Cloud Relay account can play audio in your building, so anyone who learns its password can too. Turning on two-step verification removes almost all of that risk and takes about a minute.
In the dashboard, click 2FA in the top bar (or go straight there), then Start setup. You will need an authenticator app — Google Authenticator, Microsoft Authenticator, Aegis, 1Password and Bitwarden all work. Choose “enter a setup key” in the app and type in the key shown, then enter the 6-digit code the app produces. Nothing is switched on until that code is accepted, so a mistyped key cannot lock you out.
You are then shown ten recovery codes. Write them down and keep them somewhere other than your phone. Each works once, and they are the way back in if the phone is lost — we store only hashes and genuinely cannot recover them for you.
After that, signing in asks for your password and then a code. Your devices are unaffected: they keep running to schedule whether or not anyone is signed in.
“The Multilarm program file has changed”
Multilarm checks its own program file each time it starts. If the file changed and it was not one of our updates, it records a fault, shows it on the Diagnostics page and in the dashboard, and emails the account owner.
Multilarm keeps running when this happens — a public address system that refused to start because a file changed would leave a building without its announcements, which is the worse outcome. The message is there so somebody looks.
If you did not replace the program yourself, treat that device as untrusted: reinstall from multilarm.com (checking the fingerprint as above), change the device's login password, and rotate its Cloud Device Token from the dashboard.
Rotating a device token
A device token is the credential that lets the Cloud Relay control that device. If it has been shared too widely, an installer has moved on, or you suspect a device has been tampered with, replace it: in the dashboard, find the device and click 🔄 Rotate token.
The old token stops working straight away. The device shows as offline until you set the new token on it — press Ctrl+K at its console, or use the ready-made --cloud-token command the dashboard offers. Its alarms and schedule keep running the whole time; losing the cloud connection is not the same as losing the alarms.
Contact & Support
Feedback, suggestions, bug reports and general enquiries are all welcome.
Need an answer right now? Every page on multilarm.com has a Help button in the bottom-right corner. It opens Multilarm Assist — browse help topics, ask a question in plain English, or walk a step-by-step fix for the common problems (device offline, no sound, claim codes, wrong bell or prayer times, text-to-speech, updates, billing). Answers come from the documentation inside your own browser, so it works instantly and privately; if it can’t help, the same window emails support with your conversation attached for context. Signed in to the Cloud Dashboard, that email also carries an automatic diagnostic snapshot of the device you pick.
What happens after you write to us. Whether you use the contact form, the Help window or email hello@multilarm.com directly, you get an immediate acknowledgement carrying a reference number and a few links that often answer the question on the spot. Quote that reference if you write again, and keep the reply in the same email thread so everything stays together. The acknowledgement is automatic; the answer that follows is written and checked by a person, normally within one working day.
Web repository & all downloads
@AliMuhammadK62 — support development
Comments & Feedback
Community Comments
- Loading comments…