A minimal-effort, control-first Hubitat dashboard — select your devices and you're done. Most dashboards are built around viewing status; this one is optimized for doing things — large touch targets, drag-to-dim, and bulk actions so you can turn off a whole room, the whole house, or adjust multiple thermostats at once. No layout builder, no grouping rules, no token copying. The app groups everything by Hubitat room, strips redundant room prefixes from device names, and presents a clean, touch-friendly UI. Optional tweaks (theme, favorites, nav order, PINs) are available when you want them, but nothing is required to get a usable dashboard.
It is a PWA you can install on your phone, includes a simple scheduler you can manage remotely without logging into the Hubitat admin UI, and runs completely on your hub — no Maker API, no third-party cloud backend.
Works over both the local URL and Hubitat's cloud proxy, so the same experience works at home and away.
Supports lights (dimmers, switches, CT, RGB), outlets, motorized shades, ceiling fans, thermostats, locks, garage doors, HSM, Hubitat scenes, hub mode, music/media players, sensors, live camera views (go2rtc and native RTSP, local URL only), notification popups and Favorites notification tiles, and a built-in scheduler for lights, outlets, thermostats, and hub mode. Favorites also support HTTPS embed cards, live clock tiles, and HTML tiles (Tile Builder and similar). Designed to show ~130 lights on one page, within Hubitat's 128 KB cloud response cap.
- What makes it different
- User guide
- Lights & rooms
- Light snapshots
- Thermostats
- Motorized shades & blinds
- Ceiling fans
- Locks & garage doors
- Hubitat Safety Monitor (HSM)
- Hub mode & scenes
- Music & media
- Cameras
- Sensors
- Notifications
- Dashboard triggers
- Scheduler
- Synagogue
- Favorites
- Search, collapse & reorder
- UI preferences
- Local vs cloud mode
- Real-time updates (WebSocket)
- PWA installation
- Get started
- Installation
- App preferences (hub)
- Developer docs
- Security
- Changelog
- Control-first, not status-first — the UI is optimized for acting on devices quickly: drag-to-dim, one-tap room/house on/off, multi-thermostat control, and other bulk actions. Status is there when you need it; control is the priority.
- Minimal-effort configuration — install the app, pick devices in Hubitat preferences, open the link. Rooms and layout come from your Hubitat room assignments. Customization is optional, not required.
- Installable PWA — open the cloud URL on your phone and use Install app in the menu (Android Chrome installs directly; iPhone and iPad get Add to Home Screen steps).
- Simple remote scheduler — create daily, weekly, one-time, sunrise/sunset, and mode-change schedules from the dashboard itself. No Hubitat login, no Rule Machine, no external service — just the same OAuth dashboard URL.
- Runs completely local on your hub — UI, API, scheduler, snapshots, and
favorites all live on the hub. Cloud access is optional via Hubitat's own
cloud.hubitat.comproxy.
This section documents every feature in the app — including the practical details that do not belong in a forum announcement.
The main view groups selected light devices (switches and dimmers from the app preferences) by Hubitat room. Device labels have the room name stripped when it would be redundant — e.g. a device named "Kitchen Island" under the Kitchen room header shows as Island, not "Kitchen Island".
| Action | How |
|---|---|
| Toggle on/off | Tap the tile |
| Dim | Drag horizontally on the tile fill (touch or mouse) |
| Color / white balance | Tap the device name to open the color popup |
| Room all on / all off | Use the On / Off buttons in the room header (lights only) |
| Whole house all on / all off | Use All on / All off in the top bar (lights only) |
Rename: On Lights, Favorites, Blinds, Fans, Sensors, Thermostats, or Music, open More options → Rename, then tap a name. Lights and Sensors can also rename a room title. Done leaves the mode. A device rename writes Hubitat’s Device Label (the name shown here and on the Devices page). The Device Name is left as-is. A room rename writes the Hubitat room name and keeps that room’s devices. Unassigned is not a room. Favorites show the full device label; room tiles still drop a leading room name.
Color popup: RGB bulbs get white (color temperature) and/or color tabs as supported by the device. Changes apply live while you adjust; click outside the popup or press Escape to dismiss. Tap the tile body (not the name) to toggle on/off without opening color controls.
Outlets: Devices selected under the Outlets picker use socket-style tiles so they are easy to tell apart from lights. By default they appear in the same room layout as lights. Enable Show outlets in separate Outlets tab in the companion app to move them to the Outlets quick-nav view instead. Tap an outlet tile to toggle it. Room and whole-house On / Off (and snapshots) control lights only — outlets are never included in bulk lighting control.
Room climate: If a thermostat or temperature sensor is in the same room, the room header shows the current temperature. Tap the thermostat icon to open the dial popup for that unit (when the device is a controllable thermostat).
Bulk on/off confirmations: Whole-house All on and All off show a confirmation dialog before sending commands. Room on/off does not.
Command metering: By default the hub sends light commands one device at a time with a short delay between each (configurable in app preferences). This helps avoid flooding Zigbee/Z-Wave networks when turning many lights on or off at once.
Snapshots save the current on/off, level, color temperature, and RGB state of lights so you can restore them later. They are stored on the hub (not in the browser) and sync to every device that opens the dashboard.
What is captured per light: switch state, level (dimmers), color temperature, and hue/saturation (RGB bulbs).
Room snapshot
Each room header has On / Off slide tracks:
| Gesture | Off track | On track |
|---|---|---|
| Quick tap | Turn all lights in the room off | Turn all lights in the room on |
| Press & hold (~0.4 s), then slide | Save Current State | Restore Saved State |
Slide toward the revealed action label and release at the end of the track to commit. Restore is only available after a snapshot has been saved for that room.
Whole-house snapshot
The top-bar All off / All on buttons work the same way:
| Gesture | All off | All on |
|---|---|---|
| Quick tap | Turn off all lights (with confirmation) | Turn on all lights (with confirmation) |
| Press & hold, then slide | Save Home State | Restore Home State |
Tips
- Save before changing lighting for a party, movie, or cleaning — restore when you are done.
- Snapshot restore runs commands through the same metered queue as bulk on/off. Large restores may take a few seconds.
- Activation optimization (app preference) skips level/CT/RGB commands during restore when the device already reports the expected value.
Select thermostats in the app preferences. They appear in the Thermostats quick-nav popup (when enabled) and in room headers when assigned to a room.
- Per-thermostat dial: heat/cool setpoints, mode, and fan mode/speed (uses
fanAuto/fanOn/fanCirculatewhen the driver supports them). Extra Comfort controls appear only when the device exposes them:- Dry / Fan modes from
supportedThermostatModes(sendssetComfortModewhen that command exists) - Fan speed (
auto/quiet/low/medium/high/powerful) when the driver hassetComfortFanSpeedorcomfortFanSpeed - Vane position when the driver has
setVanePositionorvanePosition
- Dry / Fan modes from
- All thermostats: top-bar button (when multiple thermostats are configured) opens a central control with a multi-select target menu — choose which units to adjust, then apply mode or setpoints to the selection
- Reorder: on the Thermostats tab, overflow Reorder lets you drag or move cards; the order is saved on the hub and syncs across devices
- Mode pill: the round HVAC-mode control keeps a fixed size; long mode names scale down so they stay inside the pill
- Compact favorites: thermostat favorites can use Compact size — a mini ring shows current temp with setpoint and mode beside it; tap opens the full dial
Hide the thermostats quick-nav icon via Show thermostats in dashboard quick menu in app preferences if you only use per-room headers.
Shades and blinds appear in the Blinds quick-nav popup and as tiles grouped by room on that view. App preferences use three pickers because Hubitat drivers advertise different capabilities:
| Preference picker | Capability | Use when |
|---|---|---|
| Window Shade drivers | windowShade |
Standard motorized shade drivers |
| Window Blind drivers | windowBlind |
Drivers that use Window Blind (including tilt) |
| Dimmer / Switch Level drivers | switchLevel |
Drivers that only look like a dimmer (no Window Shade) — common for Hubitat Virtual Shade and many community motors |
Limitation (Switch Level list): Hubitat device selectors filter by capability
only. The dimmer / Switch Level picker lists every dimmable device on the hub
(lights, dimmers, and shade drivers that use setLevel). Select only devices
that are actually shades or blinds. Do not pick ordinary lights here — put those
under Lights. There is no Hubitat API to hide non-shade dimmers from that list.
Commands prefer shade APIs when present (open / close / setPosition /
stopPositionChange), and fall back to switch/level (on / off / setLevel /
stop) for dimmer-style drivers. Position and status can come from level /
switch when position / windowShade are absent.
- Open / close buttons (and Stop when the driver supports
stopPositionChange/stop) - Drag the position slider to set shade level — only shown when the driver supports
setPosition/setLevel(open/close-only motors do not show a dead slider) - All blinds: top-bar button on the Blinds tab opens a central control with a multi-select target menu — choose which shades to adjust, then open, close, or set position for the selection
- Favorites star works on shade tiles
Select devices with the FanControl capability. They appear on their own
Fans tab (or popup). Hubitat exposes discrete speeds (typically
low/medium/high for AC fans; DC fans report whatever list the driver supports
via supportedFanSpeeds).
- Tap the fan icon to turn on or off (on restores the last speed on the hub)
- Use + / − to step through supported speeds
- All fans: top-bar button on the Fans tab opens a central control with a multi-select target menu — choose which fans to adjust, then use the fan power button (same as per-fan tiles) to turn all selected fans on or off, or pick a common speed
- Favorites star works on fan tiles
Select lock devices and garage door openers in the Locks & garage app preferences section. The Locks quick-nav popup lists all selected locks and garage doors with lock/unlock or open/close controls.
- Unlock PIN (optional, app preference): when enabled, unlocking a lock or opening a garage door from the dashboard requires entering a PIN on an on-screen pad. Locking and closing garage doors never requires a PIN. The PIN is validated by this app before the command is sent.
- Compact favorites: lock favorites can use Compact size — tap to lock/unlock; unlocked shows an open lock in red, locked shows a closed lock
HSM control is off by default. Enable HSM security control in app preferences to show the Security quick-nav icon.
- View current HSM status and any active alert
- Arm home / away / night, disarm all, cancel alerts
- HSM PIN (optional): require PIN before arm/disarm commands
- Status colors reflect armed, arming, disarmed, monitoring, and alert states
- Hub mode quick-nav popup lists your hub's location modes; tap to activate
- Scenes quick-nav popup lists native Hubitat scenes from
location.scenes; tap to activate. No separate scene picker in app preferences — all hub scenes are available automatically
Hub mode can also be used as a scheduler trigger or scheduler action (see Scheduler).
Three device pickers in app preferences. Devices that appear in more than one list are shown once.
| Picker | Typical devices | Controls |
|---|---|---|
| Music / media players | Sonos, Echo Speaks, AirPlay | Transport (prev/play-pause/stop/next when supported), volume, current track |
| Additional speakers | Chromecast, Google Home, Bluetooth speakers with volume | Play/pause/stop, volume (per device capabilities) |
| Media transport | HomeKit speakers, TVs / set-top boxes | Play/pause/stop (and volume when advertised) |
The Music quick-nav popup lists all configured players. The top-bar All music button appears when multiple players are selected. An animated equalizer on the album icon indicates playback (respects reduced-motion preferences).
TTS-only speakers (speak / playTrack with no volume or transport) are not listed — use Rule Machine for those. C-8 Pro BTHome sensors belong on the Sensors tab, not Music.
A simple live-view grid for go2rtc Camera devices (from the go2rtc Hubitat app) and native RTSP Camera Stream devices (Hubitat C-8 Pro). This is not a full NVR — use your camera app for recordings, PTZ, and other advanced features.
How native RTSP works: the hub pulls your camera’s RTSP stream (typically
H.264) and re-publishes it as MJPEG at /hub2/videoStream/<deviceId>.mjpg for
browser playback. mDash uses that hub endpoint — not the raw rtsp:// URL.
Requirements
| Requirement | Why |
|---|---|
| Category tabs enabled (overflow menu ⋯) | Cameras is a tab, not a quick-nav popup |
Local hub URL (http://<hub-ip>:8080/...) |
Streams are HTTP on your LAN; the tab is hidden on the cloud HTTPS URL to avoid mixed-content errors |
| Cameras selected in app preferences | Cameras (go2rtc) and/or Cameras (native RTSP) pickers |
| Native RTSP only | C-8 Pro hub with platform 2.5.1.138+ |
Controls
| Action | How |
|---|---|
| Watch live stream | Open the Cameras tab; streams start when a tile scrolls into view |
| Switch to HD | Tap HD on a go2rtc tile (when a main/high stream is available); native RTSP has one stream |
| Reorder cameras | Overflow menu → Reorder; drag or use arrows; order syncs to the hub |
| Change layout | Overflow menu → 1 / 2 / 3 columns (saved per browser) |
Streams stop when a tile scrolls off screen or when you leave the Cameras tab, to keep hub CPU and network load low (especially for native RTSP MJPEG).
Most sensors are read-only on the dashboard. Select them in the Sensors section of app preferences (motion, contact, water, presence, humidity, illuminance, smoke/CO, valves) plus Temperature sensors for display-only temperature.
C-8 Pro BTHome / Shelly BLU devices (Bluetooth Integration) use the matching typed lists. Occupancy-only and button devices that do not match a typed picker go under Other / generic sensors. BTHome is not listed on the Music tab.
The Sensors quick-nav popup aggregates all selected sensors and valves. Temperature sensors also appear in room headers. Battery percentage is shown when the device reports it. Valves show open/close controls on their cards.
Multi-capability devices show one tile: the primary reading is large, and up to four additional readings appear as secondary lines on the card (humidity, light level, pressure, CO₂, and so on). Temperature-only selections also surface other environmental readings when the hardware reports them.
Security sensors (motion, contact, shock/glass-break, leak, smoke, presence) show when the device last reported activity in the card footer (for example, "Last activity · 3 min ago").
A device selected in both Temperature sensors and Humidity sensors (or Illuminance sensors) appears once as a Temperature tile with the other reading secondary. Selecting both Temperature and Other / generic sensors keeps the generic reading as primary with temperature in the footer. Other multi-picker overlaps appear once, using the first matching type. Filter chips reflect the merged tile type (for example, temp+humidity counts as Temperature).
Organization: by default sensors are grouped by Hubitat room. In the overflow menu, enable Do not use rooms for organization to show one flat list grouped by sensor type instead; each card still shows its room in the meta line. This preference is stored per browser.
Hubitat has no built-in virtual notification device. This package includes a
mDash Notifications driver (capability.notification) so Rule Machine and
other apps can send messages to the dashboard.
Setup
- Install/update Modern Dashboard (HPM installs the mDash Notifications driver).
- In Apps → Modern Dashboard → Notifications, tap Create popup mDash Notifications device and/or Create tile mDash Notifications device (optionally set a name first).
- Assign devices to Popup notification devices and/or Tile notification devices.
- In Rule Machine (or another app), send a notification to the appropriate device.
Each Create button adds a separate mDash Notifications child and selects it in the matching picker. A device in both pickers is treated as popup-only.
You can rename or remove created devices under Devices like any other device,
remove them from the dashboard picker, or add other capability.notification devices.
Popup notifications — unread messages appear as a banner over the dashboard (one at a time, FIFO queue):
| Button | Behavior |
|---|---|
| Dismiss | Removes it on the hub so every open dashboard stops showing it |
| Mark as Read | Same hub-wide dismiss |
| Escape | Same hub-wide dismiss |
Tile notifications — on the Favorites tab, use Add tile → Notifications (or the empty-state button) to add a resizable notifications list tile. Messages from Tile notification devices appear newest-first with device name and time. Tap the × on a row to mark it as read (hub-wide). You can add multiple notification tiles; they all show the same tile queue.
Sounds apply to popup notifications and dashboard trigger tones (off by default). Enable Notification & trigger sounds in the overflow Preferences menu. The browser will ask for notification permission when you turn sounds on. Trigger tones also require the companion sound arm / shunt switch to be ON (see Dashboard triggers).
Always-on tablets can react to Hubitat events in the browser — no native app on the tablet. Rules are evaluated on the hub; open dashboards fetch a slim action queue.
Setup
- In Apps → Modern Dashboard, expand Dashboard triggers (closed by default).
- Enable tablet triggers, optionally pick a quiet-hours switch (ON = sounds allowed), set how long cameras stay up by default (60 seconds), and choose the doors, motion sensors, and buttons/doorbells you might use.
- Open Set up tablet triggers… and create triggers (max 6). Each one is a plain story: when a door opens / motion is detected / a button is pressed → optional camera, sound (chime or alert), and message. A live preview updates as you choose.
- Optionally use Send a test to open dashboards to enqueue a sample action.
- On each tablet, enable Notification & trigger sounds if you want tones. Use overflow Trigger tones armed (or Rule Machine on the quiet-hours switch) when you want silence.
Behavior
- Camera overlays are local URL only, near full-screen, muted by default, with a visible Dismiss control, Escape, and hub auto-dismiss. go2rtc overlays prefer the high/main stream when available.
- While a camera overlay is up, related notification text shows as a caption; after the overlay ends, unread notifications still appear as the normal popup.
- Shunting silences tones only; overlays and notification text still fire.
- Dismissing a camera overlay (or its auto-dismiss) clears that action on every tablet. It does not mark the captioned notification as read.
Open the Scheduler quick-nav icon to create schedules without logging into
the Hubitat admin UI. Schedules are stored on the hub and fire via Groovy
schedule() / runOnce() — they work remotely through the same OAuth dashboard
URL.
Triggers
| Type | Description |
|---|---|
| Daily | Same time every day |
| Weekly | Same time on selected days of the week |
| One-time | Specific date and time; self-deletes after firing |
| Sunrise / sunset | Daily or weekly, with minute offset (uses hub sun times) |
| Hub mode change | Fires when the hub enters a selected mode |
Time-based schedules can optionally restrict to modes (only fire when the hub is in one of the selected modes). This condition does not apply to mode-change triggers.
Actions
| Target | Options |
|---|---|
| Lights | Per-room or per-device; on/off; dim level; color temperature (CT devices) |
| Outlets | Per-room or per-device; on/off only (devices from the Outlets picker) |
| Locks | Per-room or per-device; lock or unlock. A scheduled unlock does not ask for the PIN |
| Blinds | Per-room or per-device; open or close; position when that shade supports it |
| Fans | Per-room or per-device; on or off; speed from the speeds that fan reports |
| Thermostats | Mode, heat/cool setpoints, fan mode |
| Hub mode | Set location mode |
Each schedule row shows last run and next run. Use the per-row toggle to enable/disable, or Run actions now to fire immediately (ignores pause and mode restrictions). Times follow the hub timezone and display in 12h or 24h format per the Use 24-hour time in scheduler app preference (stored internally as 24h for reliable firing).
On the cloud URL, schedules load when you open the Scheduler (GET /schedules)
instead of arriving with every /data poll, so the main payload stays under
Hubitat Cloud's size limit. Local mode includes schedules in /data as usual.
Schedule files for an assistant
In the Hubitat app, open Dashboard options — advanced, then Upload schedules….
That page shows the schema and a download for it, and a download of the device
list. The list is the devices selected in the app and only the controls a
schedule can set, plus hub mode names. Give both to your assistant, then paste
the JSON it returns on that same page. Upload previews the file. Submit
saves the green rows. The schema file is
lib/schedule-upload.schema.json.
When mDash Shabbat and Holidays is installed, that same page also shows the Shabbat and holidays schema and accepts that file in the same paste box. The holiday schema is hidden when the module is not installed.
A schedule whose name already exists is replaced. Devices are matched by name to the lights, outlets, locks, blinds, fans, and thermostats selected in the app.
{
"schedules": [
{
"name": "Porch at sunset",
"trigger": { "kind": "daily", "when": "sunset", "offsetMin": 0 },
"action": {
"target": "lights",
"states": [{ "name": "Porch", "on": true, "level": 40 }]
}
}
]
}trigger.kind is daily, weekly, once, or mode. Clock times use
"when": "clock" and "time": "19:30". Weekly schedules add "days": ["MON","FRI"].
One-time schedules use "at": "2026-10-09T19:30" in hub local time. Omit
enabled to leave the schedule on.
mDash Synagogue is a separate package. Leave it uninstalled unless you want it. After Hubitat Package Manager installs it, open Modern Dashboard and tap Done so the hub can start the child app. A Synagogue tab then appears.
The tab is where you program the building. The hub computes the times. Set up a space, such as the sanctuary, with the lights, outlets, locks, and thermostats already selected in Modern Dashboard. Each space has cues: heat an hour before, lights two minutes before, and lights off at the end. Services are scheduled by day: weekdays, Shabbat, and each holiday. A holiday can use the Shabbat schedule as it is, or start from it and change it. A time can be a clock time or a number of minutes before or after a HebCal time, such as sunset. The hub location has to be set under Settings, Hub Details.
Calendars takes a secret https or webcal link, such as a Google Calendar iCal address. The hub fetches it. The link stays on the hub and is shown only by its last six characters. A title rule sends matching events to a space, and those events join the same timeline as the services, including the stay-on gap. One-time bookings do too. All-day events are ignored. A repeat the hub cannot apply is named and skipped.
Closed dates stop services for a stretch, such as a renovation or a summer weekday break. Weekday closures leave Shabbat and Yom Tov running. A service that has already started keeps its end cues, so a room is not left on. A closure can also stop bookings and calendar events. Guest door codes are not stored here. Put those in Hubitat's lock code tools. A booking still unlocks at the start and locks at the end through the space's cues.
Warm up earlier moves only the heat for one service. It does not change the saved program, and it does not move lights.
Today's times is a strip at the top of Agenda. It uses the times the hub already loaded. It does not add a tile to the main dashboard.
Alerts are for problems only: a device did not respond, a scheduled unlock was skipped because it was too late, or the times or a calendar are out of date. Choose the phones in the Hubitat app, under Synagogue, not in the dashboard. Nothing is sent during Shabbat or Yom Tov. If something goes wrong then, one message is sent after it ends. Nothing is sent overnight for an out-of-date calendar or times.
Backup downloads the schedule so it can be restored after a hub reset or a bad edit. Calendar links are not in the backup. After a restore, paste each link again. Restoring replaces the schedule and can be undone for a short time.
AI assistant (MCP)
In the Hubitat app, turn on Allow an AI assistant to create schedules. The page shows a link on your home network. Point the assistant at that link. It can list devices and create, change, and delete schedules. It does not ask for the dashboard password.
There is no cloud assistant link. Away from home, open Upload schedules… in the Hubitat app, give your assistant the schema and device list, and paste the JSON it returns.
Import from Simple Automation Rules
In the Modern Dashboard Hubitat app (not the dashboard UI): Dashboard options → Import Simple Automation Rules…. Export rules from Hubitat (Apps → gear → Export/Import/Clone), paste the file contents, preview what will import, then Import.
Only schedules the mDash scheduler can run are imported (specific time / sunrise /
sunset, hub mode change, optional mode restrictions, Turn On / Off / Set Level /
Set Temperature on devices already in the Lights or Outlets pickers). A
Simple Automation “second time” imports as a second schedule with the opposite
on/off (matching SAR’s anti-action), named with (on) or (off). Unsupported rules are listed with a reason
and are not created. Re-importing the same export replaces prior imports from
those rule ids. Disable the original Simple Automation Rules after you verify
the new schedules.
Not imported (by design): device/motion/contact triggers, Mode Transition
(from→to), leave-mode offMode pairs, and Toggle. Create those manually in the
Scheduler if needed.
Optional separate package. In Hubitat Package Manager, install mDash Shabbat
and Holidays only if you want this feature. That package installs
mld-holiday.js. Modern Dashboard does not install the file. When the file is
in File Manager, Shabbat & holidays turns on by itself. Do not add the holiday
app from the Modern Dashboard app page. Hiding the scheduler also pauses this
module.
The wizard asks where you are (diaspora or Israel), which hub mode to enter at candle lighting, and which mode to return to at the end. Shabbat is set up first. Each Yom Tov can use that schedule as-is, start from a copy, use a new schedule, or be skipped. Skipped holidays do not change the hub mode. A Shabbat that falls on or next to a skipped holiday still runs.
Holiday files use the same Upload schedules… page. The Shabbat and
holidays schema is shown there only when this module is installed. Paste the
JSON or choose the file, tap Upload to preview it, then tap Submit.
An occasion in the file replaces that occasion's choice. Template slots included in the file replace those slots.
Slots left out stay as they are, and an empty list clears a slot. Occasions left
out of the file stay as they are. Devices are matched by name. If a name and an
id are both set and they are different devices, that occasion is skipped. The schema file is
lib/holiday-upload.schema.json.
{
"occasions": [
{
"id": "shabbat",
"choice": "own",
"template": {
"start": { "states": [{ "kind": "light", "name": "Dining", "on": true, "level": 40 }] },
"end": { "states": [{ "kind": "light", "name": "Dining", "on": false }] }
}
},
{ "id": "yomKippur", "choice": "shabbat" }
]
}Candle-lighting and havdalah times come from HebCal for the hub’s latitude and longitude. A Jewish day runs from candle lighting until the next candle lighting or havdalah, so the second night of a holiday is after nightfall. Rosh Hashana is two days in Israel as well. Chol HaMoed, Chanukah, Purim, and fast days are not included.
On the Schedules list, each upcoming occasion is one short row. Tap it for the full schedule: a timeline per light or outlet, in the hub’s time zone, with on and off labeled in text. Timeline by light shows one light across upcoming occasions.
If the hub is in a mode you marked “do not start” (for example Away) at candle lighting, nothing starts. Switching the hub into the holiday mode during that span continues it. Switching to Home does not. If the hub was off, light and outlet actions from the last two hours that never ran are applied when it comes back (only the latest state for each device). Older missed light actions are not replayed. The holiday mode is still corrected for a span that already started, unless that span was held because the house was Away.
If Shabbat and Holiday Scheduler is also installed, turn off its mode switching so the hub is not switched twice. Rule Machine and motion rules should be limited to modes other than the holiday mode. mDash schedules with no mode restriction still run during the holiday; the wizard lists them.
Tap the star on a supported device tile (lights, shades, locks, garage doors, music, sensors, etc.) to add it to favorites. The list is stored on the hub and syncs across devices. Open the Favorites quick-nav icon for a cross-category view of starred devices. On the Favorites tab, use overflow menu (⋯) → Reorder/Resize to drag tiles or use the move buttons, and tap Size on a tile to choose a named layout (Compact, Standard, Wide, Square, Portrait, Full row, Tall, Large, or Fill screen depending on device type). One size is saved per tile and adapts responsively across phone and desktop widths. Adjacent Compact tiles pair into shared cells (two high on phones; up to four side by side on wide layouts).
From Favorites, overflow Add tile (or the empty-state buttons) also adds non-device cards: Embedded, Time, Notifications, and HTML.
Embed cards: Use Add tile → Embedded to add an HTTPS iframe widget — for example a Google Calendar embed
URL or an iframe-based weather widget. You can paste either the HTTPS URL or a
full <iframe …> snippet; only the src is kept. Cards support sizes
Compact, Standard, Wide, Square, Portrait, Full row,
Tall, Large, and Fill screen, plus a temporary
Expand overlay. Use Open if the site refuses to load in a frame (many
normal website pages block embedding; public Google Calendar embeds usually work,
while private calendars may require an existing Google sign-in in that browser).
Only https:// sources are accepted so embeds work on the installed cloud PWA.
Embedded sites see your IP address and may use cookies already set for that
provider. With category tabs on, Favorites keeps embed iframes mounted while you
switch tabs (hidden, not destroyed), so in-widget state like a Google Calendar
view is preserved. Browser third-party cookie rules still apply after a full
page refresh.
Time tiles: Use Add tile → Time for a live clock card. Choose a style — Just the time, Time with seconds, or Time with date — and a size preset. Time tiles reorder with other favorites and sync across devices.
Notification tiles: Use Add tile → Notifications for a resizable list of unread messages from Tile notification devices (see Notifications).
HTML tiles: Select HTML source devices in the Hubitat app (HTML tiles section) —
for example a Tile Builder Storage
Driver, a vehicle status device, or any driver that publishes static dashboard HTML.
Then on Favorites use overflow Add tile → HTML and pick one or more discovered
attributes (Tile Builder tile1–tile26 expand automatically). Inline HTML renders
in a sandboxed frame with a light mDash theme bridge (font, text color, transparent
background); source-defined colors stay intact. Oversized Tile Builder tiles that
point at hub File Manager URLs work on the local dashboard; cloud HTTPS may block
those local http:// stubs. Scripts and interactive JS are not supported. Only
favorited/active tiles load HTML bodies (lazy when scrolled into view) so /data
stays small. In Favorites reorder mode, Size opens card-size presets; HTML tiles
also get a Zoom row (50% / 75% / 100% / 125% / 150%) to scale content inside the
card.
Search — the sticky search bar filters lights and rooms by name. Matching rooms auto-expand; non-matching tiles are hidden.
Collapse — tap the chevron on a room header to collapse/expand. The top-bar expand/collapse-all button toggles every room.
Reorder — overflow menu (⋯) → Reorder:
- Rooms: drag handles appear; drag rooms to change display order. Tap Done to save to the hub (syncs across devices).
- Quick-nav icons: drag category icons (locks, scenes, scheduler, etc.) to reorder. Search is hidden while reordering.
- Favorites tab: drag handles and move buttons reorder favorite tiles; the Size control opens a named size chooser (and Zoom for HTML tiles); order, sizes, and special tiles sync across devices.
- Thermostats tab: drag handles and move buttons reorder thermostat cards; order syncs to the hub. Lights still reorder rooms and quick-nav icons.
Stored per browser in localStorage (overflow menu ⋯):
| Setting | Description |
|---|---|
| Theme | Dark, Light, or Auto (follows system) |
| Haptic feedback | Short vibration on supported mobile browsers |
| Notification sounds | Off by default; uses OS notification sound when enabled (OS toast is closed right away) |
| Category tabs | Show Lights / Favorites / Sensors / etc. as tabs instead of popups |
| Navigation drawer | Move search and category icons into a side drawer; top bar shows active category |
| Do not use rooms for organization | Sensors view: flat list by type instead of by room (see Sensors) |
| Camera columns | On Cameras tab: 1 / 2 / 3 column layout (see Cameras) |
| Local hub URL | Used for local-mode switching (see below) |
The app page shows two URLs:
| URL | When to use |
|---|---|
| Local | http://<hub-ip>:8080/... — fastest at home on your LAN |
| Cloud | https://cloud.hubitat.com/... — works anywhere via Hubitat's proxy |
Both URLs include the OAuth access_token and serve the same dashboard. API
calls use relative paths, so they stay on whichever origin you opened.
The Cameras tab is available only on the local URL (see Cameras).
Switching modes
- Open local mode / Open cloud mode in the overflow menu navigate between stored URLs.
- The local hub URL field is pre-filled from the hub on first load; edit it if your hub IP changes.
- On Android, when you open the cloud URL, the app probes your local hub URL with a one-time nonce. Chrome may ask once for permission to access devices on your local network. If the hub echoes that nonce, a banner offers to switch to faster local mode. Dismiss or tap Switch. Away from home the probe fails and no banner appears.
- Choosing cloud mode sets a
prefer cloudflag so Android does not suggest local mode on that device.
The nonce is unique on every request, and both client and hub disable caching, so a response from a previous visit cannot produce a false match. The LAN probe is still best-effort: unsupported browsers or denied local-network permission will block it even at home. Use Open local mode in the menu if the banner does not appear when you expect it.
iOS PWA and local mode — important limitations
- Install from the cloud URL. iOS Add to Home Screen requires the HTTPS cloud link. You cannot install a full standalone PWA from the local HTTP URL. On an iPhone or iPad, Install app in the menu explains the Share sheet steps. It stays hidden when the dashboard is already open from the Home Screen.
- Installed PWA stays on the cloud origin. The home-screen app loads
cloud.hubitat.com. That is correct for remote access and PWA install. - Switching to local mode leaves the PWA origin. If you tap Open local
mode inside the installed app, the browser navigates to
http://<hub-ip>. On iOS this typically drops you out of the installed PWA context into a regular browser tab — you lose the standalone app chrome until you reopen the home-screen icon (which returns to cloud). - No Android-style local banner on iOS. iOS does not show the "switch to local mode" banner.
- WebSocket is local-only (see below). An installed iOS PWA using the cloud URL will not get LAN WebSocket updates; polling still works.
- Practical recommendation for iOS: install the PWA from the cloud URL for everyday and remote use. If you want maximum LAN speed at home, bookmark the local URL separately — but treat it as a browser bookmark, not the installed PWA. Do not expect to combine "installed PWA" and "always on local HTTP" on iOS in one home-screen icon.
When Enable real-time updates on local network (eventsocket) is on in app
preferences (default: enabled), the dashboard connects to
ws://<hub-ip>/eventsocket while you are on the local URL.
| Local URL | Cloud URL | |
|---|---|---|
Polling (/data) |
Yes | Yes |
| WebSocket | Yes | No — cloud proxy does not expose eventsocket |
What WebSocket updates: device switch/level/color changes, thermostat attributes, lock state, shade position, music player state, sensor readings, battery, HSM status, hub mode, and notification events — without waiting for the next poll.
Caveats
- The eventsocket interface is a local-only, undocumented Hubitat feature and may change in future hub firmware. Polling is the reliable baseline; WebSocket is an enhancement.
- When WebSocket is connected, the poll interval may lengthen; polling resumes fully if the socket disconnects.
- Polling pauses when the browser tab or PWA is hidden and resumes when you return.
Use the Cloud link from the app page (cloud.hubitat.com, path includes
/dashboard).
| Platform | How to install |
|---|---|
| Android Chrome | Open the cloud URL → menu → Install app |
| Desktop Chrome or Edge | Same Install app menu item, when the browser offers install |
| iPhone and iPad | Open the cloud URL in Safari → menu → Install app for the steps. Tap Share, then Add to Home Screen, and leave Open as Web App on |
The Install app item is hidden when the dashboard is already open as the installed app, and on the local http:// hub address. iOS cannot tell that the icon is already on the Home Screen while you are still in Safari, so the item can still appear in that tab. Browsers that never offer an install prompt, such as Firefox on Android, do not show the item.
The installed app opens in a standalone window branded mDash. A pass-through service worker is registered (required for Chrome install criteria) but does not cache assets — the hub must be online; there is no offline mode.
After OAuth token regeneration, open a fresh cloud link and reinstall or re-add to home screen.
- Install via HPM (recommended), bundle, or manual paste — see below.
- Apps → Add User App → Modern Dashboard → select devices → Done.
- Open the Cloud URL from the app page; install as a PWA if you like.
- Optionally open the Scheduler icon to add remote schedules without Hubitat login.
- Built for control — most dashboards emphasize status at a glance; this one prioritizes fast, confident actions, including bulk room/house lights and multi-thermostat control.
- Zero-config layout — pick devices once; rooms, ordering, and display names are handled from Hubitat room assignments.
- Looks better than the built-in dashboard — modern dark/light UI, large touch targets, sticky search, collapsible rooms, smooth dimmer sliders, thermostat dial.
- Portable across hubs — same app code on any hub. Install, pick devices, done.
- Persistent config — room order, nav order, favorites (including embeds, clocks, HTML, and notification tiles), snapshots, and schedules live in the hub's app database, so they work from any device.
- Works away from home — via Hubitat's cloud proxy; no port forwarding or VPN.
- No Maker API dependency — slim custom JSON (~8 KB for 130 lights) stays under the 128 KB cloud cap.
src/
index.html page shell
manifest.webmanifest PWA manifest (install name: mDash)
sw.js pass-through service worker
styles.css visual design (served at /app.css)
app-pre.js SVG/data constants + helpers (concatenated into mld-app.js at build)
app.js core UI (split into 5 JS File Manager chunks at build)
lib/
pwa-icons.mjs generates dashboard PNG icons at build time
app/
ModernLightsDashboard.groovy.template Groovy SmartApp
build.mjs esbuild minify + split → dist/ + HPM manifests
preview/
server.mjs local mock server (~130 lights) for UI dev
dist/
ModernLightsDashboard.groovy generated SmartApp
upload/mld-* File Manager assets (12 files)
docs/
hubitat-community-post.md Hubitat Community forum draft
hpm-registry.md HPM registry notes for maintainers
drivers/
mDashNotifications.groovy Notification driver (popup + tile)
node preview/server.mjs
# open http://localhost:4321/The mock server generates ~130 lights across 12 rooms, thermostats, sensors,
scheduler demos, and more. Edit files in src/, refresh the browser.
node build.mjsOutputs:
| file | purpose |
|---|---|
dist/ModernLightsDashboard.bundle.zip |
Manual install — Bundles → Import ZIP |
dist/ModernLightsDashboard.groovy |
HPM / manual paste into Apps Code |
dist/upload/mld-* |
File Manager assets (12 files; HPM auto-deploys) |
hubitat/packageManifest.json |
HPM manifest — app (oauth: true) + files |
dist/packageManifest.json |
Copy of the HPM manifest |
HPM_BASE_URL=https://raw.githubusercontent.com/evdev/hubitat-modern-dashboard/master/dist node build.mjsThe Groovy app does not embed the UI (Hubitat cannot compile huge blobs). The
app reads 12 files from File Manager at runtime. JS is split into
mld-app.js, mld-app-core.js, mld-app-post.js,
mld-app-post2.js, and mld-app-post3.js to stay under File Manager size limits
(constants from src/app-pre.js are merged into mld-app.js). CSS is split into
mld-app.css and mld-app-post.css. PWA assets
(mld-manifest.webmanifest, mld-sw.js, icon .b64 files) enable home-screen
install on the cloud URL. Icons are stored as base64 text because Hubitat cannot
reliably serve binary PNGs from File Manager.
Blob size rules (enforced by npm run build and npm run verify:blobs):
| Asset type | Max size | Why |
|---|---|---|
| All File Manager JS/CSS | 120 KB | File Manager’s documented ceiling is ~124 KB, but blobs near that size truncate |
Cloud-critical JS: mld-app.js, mld-app-post2.js, mld-app-post3.js |
118 KB | Hubitat Cloud OAuth/MQTT; oversized → blank cloud dashboard / missing icons |
When a chunk approaches its limit, move code across the __MLD_SPLIT* markers in
src/app.js (or CSS into src/styles.css). Do not raise these caps.
mld-index.html
mld-app.css
mld-app-post.css
mld-app.js
mld-app-core.js
mld-app-post.js
mld-app-post2.js
mld-app-post3.js
mld-manifest.webmanifest
mld-sw.js
mld-icon-192.b64
mld-icon-512.b64
- Open Hubitat Package Manager on your hub.
- Install (or search) → find Modern Dashboard → install.
- HPM installs the Groovy app, enables OAuth automatically, and deploys all 12 File Manager assets.
- Apps → Add User App → Modern Dashboard → select devices → Done.
- Open the Cloud URL shown in the app page and install as a PWA (see below).
The package is listed in HPM's default repository — you do not need to add a custom repository URL.
Updates: use HPM Update. If HPM shows the latest version but files did not change (for example after Match Up), use Repair on the package to redeploy assets. If you previously installed from a version-tagged manifest URL or an old custom-repo entry that no longer updates, use Unmatch on the old package, then install again from HPM search.
No manual OAuth toggle or File Manager upload is needed when installing via HPM.
- Run
node build.mjson your computer. - Hubitat → Settings → Developer Tools → Bundles → Import ZIP
- Upload
dist/ModernLightsDashboard.bundle.zipand wait for Bundle imported. - Apps Code → Modern Dashboard → click OAuth → enable OAuth → Save.
- Settings → File Manager — upload all 12 files from
dist/upload/(or extractfile-manager/from the bundle zip). Filenames must match exactly. - Apps → Add User App → Modern Dashboard → select your devices → Done.
- Open the Cloud URL and install as a PWA if desired.
- Run
node build.mjson your computer. - Apps Code → New App: paste the entire contents of
dist/ModernLightsDashboard.groovy. - Click OAuth and enable OAuth, then Save.
- Settings → File Manager: upload all 12 files from
dist/upload/(exact names listed above). - Apps → Add User App → Modern Dashboard → select devices → Done.
- Open the Cloud URL and install as a PWA if desired.
When updating an existing install, re-paste the new Groovy (or re-import the bundle) so the hub learns any new routes, then upload any new
mld-*files.
If Settings → Hub Login Security is enabled, expand Hub file access in
the app preferences, turn on the toggle, and enter your hub admin username and
password (from Settings → Hub Login Security — not the optional dashboard
password under Security & access). The SmartApp logs in via 127.0.0.1 and reads
File Manager assets over your LAN IP with the session cookie.
Re-enter the hub password whenever you change other app settings — Hubitat clears password fields on save.
All settings below are in Apps → Modern Dashboard (the installed app instance).
| Section | Setting | Default | Notes |
|---|---|---|---|
| Lights & outlets | Lights, outlets, separate Outlets tab | — | See device selection |
| Climate | Thermostats, temperature sensors, room cards, quick menu | — | See device selection |
| Shades, fans & media | Shades, blinds, fans, music, speakers, media transport | — | See device selection |
| Locks & garage | Locks, garage doors, unlock PIN | — | See device selection |
| Sensors | Motion, contact, water, presence, etc. | — | See device selection |
| Cameras | go2rtc and/or native RTSP cameras | — | See device selection |
| HTML tiles | HTML source devices | — | Tile Builder / vehicle status / etc.; add tiles on Favorites |
| Notifications | Popup / tile notification devices | — | Create buttons install mDash Notifications children (popup and/or tile pickers) |
| Dashboard options | Dashboard name | mDash |
Browser tab and PWA title |
| Dashboard options | Default tab | Lights | Opening tab when Category tabs is on; falls back to Lights if empty |
| Dashboard options | Refresh interval | 5 s (2–60) | /data poll interval |
| Dashboard options | Enable eventsocket | On | LAN WebSocket; see WebSocket |
| Dashboard options | Hub mode / scenes quick menu | On | Hides quick-nav only |
| Dashboard options | Scheduler | On | Hide stops schedules from running |
| Dashboard options | Import Simple Automation Rules… | — | Paste Hubitat App Export; imports only mDash-capable schedules |
| Dashboard options | Debug logging | Off | Command traces in Hubitat Logs; auto-off after 30 min |
| Dashboard options | 24-hour time display | Off | Display only; stored times are 24h |
| Light control | Disable metering | Off | When off, commands are staggered |
| Light control | Metering delay | 75 ms | 0–2000 ms between light commands |
| Light control | On/off optimization | Off | Skip on/off if device already in target state |
| Light control | Activation optimization | Off | Skip level/CT/RGB on snapshot restore if already correct |
| Security & access | Dashboard password | Off | Password required to open dashboard (7-day sliding session) |
| Security & access | HSM enabled | Off | Show Security quick-nav icon |
| Security & access | HSM PIN | Off | PIN required to arm/disarm |
| Hub file access | Username / password | — | Only if Hub Login Security blocks file reads |
| Preference | Main lights view | Scheduler | Other views |
|---|---|---|---|
| Lights (switches & dimmers) | Tiles by room | On/off, dim, CT | — |
| Outlets | Socket tiles by room, or separate Outlets tab (preference) | On/off only | Favorites |
| Thermostats | Room header + Thermostats popup (when quick menu on) | Mode, setpoints, fan; Comfort fan speed / vane when supported | All thermostats bulk |
| Temperature sensors | Room header (read-only, when room cards on) | — | Sensors popup |
| Locks | — | — | Locks popup (locks + garage doors) |
| Shades (Window Shade) | — | — | Blinds popup; All blinds bulk |
| Blinds (Window Blind) | — | — | Blinds popup; All blinds bulk |
| Shades (Switch Level) | — | — | Blinds popup; All blinds bulk — pick shades only; list also includes normal dimmers |
| Ceiling fans | — | — | Fans popup; All fans bulk |
| Music / speakers | — | — | Music popup (musicPlayer, audioVolume, mediaTransport) |
| Cameras (go2rtc) | — | — | Cameras tab (local URL only; requires category tabs) |
| Cameras (native RTSP) | — | — | C-8 Pro; hub MJPEG proxy; Cameras tab (local URL only) |
| HTML source devices | — | — | Favorites HTML tiles (discovered attributes) |
| Popup notification devices | — | — | Full-screen notification popup queue |
| Tile notification devices | — | — | Favorites notifications tile queue |
| Motion, contact, water, etc. | — | — | Sensors popup (includes C-8 Pro BTHome / Shelly BLU) |
| Valves | — | — | Sensors popup (open/close) |
| Hub scenes | — | — | Scenes popup (all hub scenes) |
| Hub mode | — | Trigger & action | Hub mode popup |
Outlets may also be selected in the Lights picker (they then behave as lights, including room/house on/off). The Outlets picker and optional separate Outlets tab only include devices selected under Outlets.
The Shades (Switch Level) picker is for shade/blind drivers that only advertise dimmer capabilities. Hubitat cannot filter that list to shades alone, so every Switch Level device appears — select only real shades/blinds, never ordinary lights (use Lights for those).
Open Logs in the Hubitat admin UI and filter for Modern Dashboard (device log filter only shows driver text, not this app). Successful device commands log at info as manual or automation {name} so you can tell a dashboard tap from a scheduler run. Failures (command errors, auth/PIN rejections, scheduler problems) are logged automatically with device and error context. Enable Debug logging in app preferences for extra traces while investigating; it turns off automatically after 30 minutes. Passwords, PINs, and session tokens are never written to the log.
- Forum release post:
Hubitat Community thread
(draft/archive in
docs/hubitat-community-post.md). - HPM: Modern Dashboard is listed in the default Hubitat Package Manager
repository — search HPM to install; no custom repository URL required. Maintainer
notes in
docs/hpm-registry.md.
- The cloud and local dashboard URLs include your OAuth access_token (Hubitat standard). Anyone with the URL can control the devices you selected in app preferences. Treat links like secrets.
- Revoking OAuth or regenerating the token invalidates old URLs — open a fresh link from the app page and reinstall the PWA if needed.
- Lock and HSM PINs are validated by this SmartApp before commands are sent; they are not Hubitat user-account passwords.
- Optional Dashboard password adds a second gate before the UI loads device data. The password is checked server-side; a signed session in browser storage renews for seven days while the dashboard is used, then expires after a week of inactivity. This does not replace the OAuth URL token — treat dashboard links as secrets either way.
- The dashboard does not implement Hubitat admin login. The optional Hub file access credentials are only for the SmartApp to read File Manager assets when Hub Login Security is enabled.
Paste the same dist/ModernLightsDashboard.groovy, enable OAuth, select devices.
Nothing to edit.
Architecture
- UI assets live in Hubitat File Manager (
mld-*files). The Groovy SmartApp serves them and implements a slim JSON API — no Maker API. - JS is split into five app chunks (+ service worker) under a 120 KB File Manager
safety cap (truncation has happened near 124 KB). Cloud-critical chunks (
mld-app.js,mld-app-post2.js,mld-app-post3.js) must stay ≤ 118 KB (cloud OAuth/MQTT). - PWA manifest and pass-through service worker enable home-screen install from the cloud URL.
Data sync
- The page polls
GET /dataon a configurable interval. Response includes devices, room/nav order, favorites (including embed/time/notification/HTML tiles), snapshots, HSM state, sun times, and config. - On the cloud URL, schedules are omitted from
/data(Hubitat Cloud ~128 KB response limit) and loaded on demand viaGET /scheduleswhen you open the Scheduler. Local/dataincludes schedules. - On the LAN, optional WebSocket pushes device events for faster UI updates.
- Commands use optimistic UI: the tile updates immediately; failed commands roll back.
- When the page is hidden, polling stops and WebSocket disconnects; both resume on return.
Commands
| Endpoint | Use |
|---|---|
GET /cmd?id=…&c=…&v=… |
Single device command |
POST /cmd/batch |
Sequential batch (room/house on/off) |
POST /snapshot/save, /snapshot/restore |
Light snapshots |
POST /lights/bulk |
Bulk on/off by scope |
POST /hub-mode, /hsm, /scene/activate |
Mode, security, scenes |
GET/POST /schedules/* |
Scheduler CRUD, toggle, test |
POST /settings/room-order, /nav-order, /favorites, /embed-cards, /time-cards, /notification-cards, /settings/favorites-layout |
Layout sync, favorites, special tiles, HTML htmlSizes / htmlZooms |
GET/POST /notifications/*, /tile-notifications/* |
Popup and tile notification queues |
GET/POST /auth/* |
Optional dashboard password gate |
All endpoints require ?access_token=… (included automatically when you open the
dashboard link from the app page).
Smart names
stripRoomPrefix() removes a leading room name from device labels when the device
is already grouped under that room — but only when the remainder starts with a
non-alphanumeric separator (space, hyphen, etc.), so names like "KitchenAid" in the
Kitchen room are not shortened incorrectly.
- No offline mode — hub must be reachable (local or cloud).
- WebSocket only on the local URL; cloud access uses polling only.
- Standalone switches (relay modules, exhaust fans, etc.) have no separate tile type. Add them to the Lights or Outlets picker to control them from the dashboard or scheduler. Outlets can appear in room cards or a separate Outlets tab (companion app preference); they are excluded from room/house on/off and light snapshots either way.
- Shade/blind drivers that only advertise Switch Level (dimmer-style) are selected via a separate picker. Hubitat cannot filter that list to shades alone, so ordinary lights and dimmers appear there too — select only real shades/blinds; put lights under Lights. See Motorized shades & blinds.
- Cloud responses are capped at ~128 KB; the slim API supports ~130 lights on one page but very large installs may need device subsetting.
- Service worker does not cache — refresh always fetches from the hub.
- iOS PWA and local-mode switching have constraints documented in Local vs cloud mode.
Copyright 2026 Ephrayim (evdev)
Licensed under the Apache License, Version 2.0. See LICENSE and NOTICE for attribution.
Source: https://github.com/evdev/hubitat-modern-dashboard
See CHANGELOG.md.