Skip to content

Guest Wi-Fi

A guest Wi-Fi network and what a guest types to use it. Two kinds, its access:

  • A code (code): an open network whose page asks for a code once you have joined, such as a hotspot voucher from the custom UniFi Hotspot Manager integration, which is found by itself.
  • A password (password): the network’s Wi-Fi password, in an input_text, a text or a template sensor.

The card shows the network’s name, the code or password and the network’s QR code, and can fetch it again or make a new one.

import { useHaGuestWifi } from "@dashhaus/core";
/** The network, its code and its join QR code: what a guest needs, and nothing to press. */
export function JoinCard({ entityId }: { entityId: string }) {
const { entity } = useHaGuestWifi(entityId);
if (entity.state === "unavailable") return <p>Guest Wi-Fi is unavailable.</p>;
if (entity.state === "none") return <p>No guest code to give yet.</p>;
return (
<figure>
{entity.qr && <img src={entity.qr} alt={`QR code to join ${entity.network ?? "the guest network"}`} width={160} height={160} />}
<figcaption>
Join <strong>{entity.network}</strong>, then enter <strong>{entity.code}</strong> on the page that opens.
</figcaption>
</figure>
);
}

The entity id is what holds the code or password. For UniFi Hotspot Manager’s sensor.<site>_voucher, its QR code image and its two buttons are found beside it by the integration’s names. For anything else, name them: the QR code image, and a button, input_button or script for each action. The QR code is an image Home Assistant serves, so draw it from the same Home Assistant the dashboard runs in; without one, the card shows none.

<HaGuestWifi> is useHaGuestWifi as a component that draws nothing of its own. It takes every option of the hook as a prop, and hands the hook’s result to its child function. Use it where hooks can’t go, such as one per item of a list.

entityIdstring
The Home Assistant entity id.
children(live: HaGuestWifiResult) => ReactNode
Draws the hook's result. The component itself draws nothing.
useHaGuestWifi(entityId: string, options?: HaGuestWifiOptions): HaGuestWifiResult

One live guest Wi-Fi for any UI: the code or password, its network and join QR code mapped together, and the two actions that fetch it again and make a new one. UniFi Hotspot Manager's companions are found beside its `sensor.<site>_voucher`; name any other's. No history: a code's day is when it was made and how often it was used.

It reads the code or password, its QR code image and what makes a new one, and its area. There is no history: a code’s day is when it was made and how often it was used.

access?"code" | "password"
`code` (an open network whose page asks for a code) or `password` (a Wi-Fi password). Default: `code` for a `sensor.*`, `password` for an `input_text.*` or `text.*`.
network?string
The network's name, where Home Assistant names none. Default: UniFi Hotspot Manager's `wlan_name`.
qrEntityId?string
The join QR code's `image.*`. Default: `image.<site>_qr_code` beside `sensor.<site>_voucher`.
newCodeEntityId?string
What makes a new code or password: a `button.*`, `input_button.*` or `script.*`. Default: `button.<site>_create`.
refreshEntityId?string
What fetches the code again: a `button.*`, `input_button.*` or `script.*`. Default: `button.<site>_update`.
name?string
Overrides the default name, "Guest Wi-Fi".
area?string
Overrides the area Home Assistant's registries resolve for the entity.
lastSeen?string
Overrides when the entity was last reachable, shown while it is unavailable.
onActionError?(error: HaActionError) => void
Called with an HaActionError when an action is refused or fails.
entityGuestWifiEntity
actionsGuestWifiHandlers
entityIdstring
The entity that holds the code or password: a `sensor.*`, `input_text.*` or `text.*`.
namestring
Its name: the `name` option, else "Guest Wi-Fi" (the integration's own names describe it, not the network).
area?string
Where it is: "Hall".
state"none" | "unavailable" | "ready"
`ready`: a code or password to give. `none`: there is none (a voucher's uses are spent), and a new one can be made. `unavailable`: neither it nor a way to make one can be reached.
access"code" | "password"
`code`: an open network whose page asks for a code. `password`: the network's Wi-Fi password.
network?string
The network to join: "Maple Guests". Absent where Home Assistant names none, and while unavailable.
code?string
What a guest types, as Home Assistant gives it: the code ("98668-49366") or the password. Only while `ready`.
qr?string
The network's join QR code, an image URL as Home Assistant serves it (relative to Home Assistant).
allowed?number | "unlimited"
How many times the code can be used, or `unlimited`. Only while `ready`.
used?number
How many times it has been used. Only while `ready`.
lastsMinutes?number
How long it lasts once first used, in minutes. Only while `ready`.
leftMinutes?number
Once used, the minutes it has left.
created?string
When the code was made, formatted against the card's clock.
lastUpdated?string
When Home Assistant last fetched the codes, formatted.
lastSeen?string
While it is unavailable, when it was last reachable: the `lastSeen` option.

The integration shows a code only while it has a use left. With none left, the entity is none while a new code can still be made, and unavailable when it can’t.

onRefresh?() => Promise<void>
Fetch the code again now: presses its refresh action (UniFi Hotspot Manager's `button.*_update`; the integration fetches every 5 minutes on its own). Answers once Home Assistant has. Only while that action is reachable.
onNewCode?() => Promise<void>
Make a new code or password: presses its new-code action (UniFi Hotspot Manager's `button.*_create`, which makes one with the integration's own uses and length, the codes already given still working). Answers once Home Assistant has. Only while that action is reachable.

Each presses its action (button.press, input_button.press or script.turn_on) and answers once Home Assistant has. A UniFi Hotspot Manager code takes the integration’s own uses and length, and the codes already given keep working.

import { useState } from "react";
import { useHaGuestWifi } from "@dashhaus/core";
/** Make a new code: the handler answers once Home Assistant has, by when the new code is in. */
export function NewCode({ entityId }: { entityId: string }) {
const { entity, actions } = useHaGuestWifi(entityId);
const [waiting, setWaiting] = useState(false);
if (!actions.onNewCode) return null;
const make = () => {
setWaiting(true);
void actions.onNewCode!().finally(() => setWaiting(false));
};
return (
<button type="button" disabled={waiting} onClick={make}>
{waiting ? "Making a code…" : entity.code ? `New code (now ${entity.code})` : "Make a code"}
</button>
);
}
import { HaGuestWifiTile } from "@dashhaus/orb";
/**
* A network with a Wi-Fi password, kept in an `input_text`: name its network, its QR code image if it has one, and
* what changes the password. New password asks first, since devices already joined then need it.
*/
export function GuestPassword() {
return (
<HaGuestWifiTile
entityId="input_text.guest_wifi_password"
network="Maple Guests 5G"
qrEntityId="image.guest_wifi_qr"
newCodeEntityId="script.new_guest_wifi_password"
/>
);
}

A new password ends the old one for every device already joined, so both skins ask before making one.

Orb’s HaGuestWifiTile and Field’s HaGuestWifiModule are useHaGuestWifi above each skin’s card. Both keep Refresh and New code in their details, never on the card, so a stray tap never makes codes. They take the hook’s options as props, plus their own:

import { HaGuestWifiTile } from "@dashhaus/orb";
import { HaGuestWifiModule } from "@dashhaus/field";
/** Featured, the tile carries the join QR code: a hall or a wall panel's guest corner. */
export function OrbGuestWifi() {
return <HaGuestWifiTile entityId="sensor.67d9d6d6ad84e044caf4621c_voucher" footprint="featured" />;
}
/** A code sensor whose companions aren't named after it: name them. */
export function FieldGuestWifi() {
return (
<HaGuestWifiModule
entityId="sensor.visitors_code"
name="Visitors"
qrEntityId="image.visitors_join"
newCodeEntityId="button.visitors_new_code"
refreshEntityId="button.visitors_fetch"
/>
);
}
entityIdstring
What holds the code or password: UniFi Hotspot Manager's `sensor.<site>_voucher`, or a `sensor.*`, `input_text.*` or `text.*`.
showControl?boolean
Compact only. false removes the inline control, shows the value in its place, and makes the row open the details. Default true.
footprint?CardFootprint
Card footprint. The skin's stylesheet sets the heights; the three names are the shared vocabulary.
defaultOpen?boolean
defaultAction?undefined

Every state of both is in Storybook: Orb and Field.