Home Assistant integration for the Ting electrical fire sensor by Whisker Labs — the plug-in monitor that watches a home's wiring for arc faults and reports a fire hazard before it becomes one. (Not the Whisker that makes Litter-Robot; different company, same word.)
Ting has no local API. The plug talks only to Whisker Labs' cloud, and everything a customer sees comes back out of it, so this integration signs in as the phone app does and reads the same three places:
- AWS Cognito for authentication, exchanged in
auth.py. - A REST endpoint for device state — hazard flags, firmware, HVAC verification, learning-mode status.
- A SignalR hub for the live voltage stream.
signalr_protocol.pyandwebsocket.pyimplement the SignalR framing directly rather than pulling a client library, so messages are decoded against the protocol's own framing instead of by scanning raw bytes for float markers.
iot_class is cloud_push: state arrives on the socket as it happens, and the
configured scan interval is a fallback for when the socket is quiet, not the
primary path.
This is reverse-engineered, and the endpoint facts are not this project's
discovery. They were recovered independently by the
aidenmitchell/ha-whisker-ting and simplytoast1/ha-whisker-ting projects,
whose implementations agree with each other; this one reuses those endpoints
and replaces the websocket client. Whisker Labs does not document or support
any of it, and can change it without notice.
One device per Ting on the account.
| entity | |
|---|---|
binary_sensor fire hazard |
the headline hazard flag |
binary_sensor electrical fault hazard |
with sensor electrical fault hazard status carrying the vendor's message |
binary_sensor unsafe frequency hazard |
with its own status message sensor |
binary_sensor frozen pipe |
device_class: cold |
binary_sensor learning mode |
the plug is still characterising the home's electrical signature |
binary_sensor HVAC verified |
|
sensor voltage, voltage high, voltage low |
live, from the SignalR stream |
sensor average peaks max |
|
sensor firmware version |
diagnostic |
- Cloud only. No account, no internet, no entities. There is no local path to fall back to.
- Entities go unavailable in a sustained outage, on purpose. A brief REST
failure carries the last reading forward — a hiccup is not the plug being
gone — but after ten consecutive failed polls every entity goes
unavailablerather than keep publishing a reading nobody can date. For a fire-hazard flag, stale and clear are not the same fact, and an entity that keeps showing the last value it saw gives you no way to tell them apart. Write availability into any automation that acts on these flags. - The live-voltage message shape is inferred. The push carries four float64
values whose order is not documented.
websocket.pytries structured field names first and falls back to positional floats, logging atWARNINGwhen it has to guess — so check the log once after installing to see which path your account took. - Learning mode matters. A newly installed Ting reports no useful hazard
state until it has characterised the home; the
learning_modesensor is there so an automation can tell that apart from "nothing is wrong".
Setup asks for two things, and only two: the email and password of the Ting account. There is no separate integration credential — this signs in as the mobile app does. One config entry per Whisker account; a second attempt with the same account aborts.
Setup tests both channels before it creates the entry: the Cognito sign-in and REST account read, and then one real connection to the SignalR voltage hub, which is a different endpoint on a different credential. If the hub refuses, setup fails and says so specifically — a green entry whose live stream cannot connect is worse than no entry at all.
Tings added to the account later appear on their own, on the next poll, and one removed from the account takes its device and entities with it. Neither needs a reload.
Options (Settings → Devices & Services → Whisker Ting → Configure) carry one setting: poll interval, 30–3600 seconds, default 60. It governs the REST poll for hazard and device state. Live voltage arrives on the SignalR socket as it happens and is not affected by it, which is why the default is unhurried. Changing it reloads the entry.
Requires msgpack, declared in the manifest and installed by Home Assistant.
Settings → Devices & Services → Whisker Ting → ⋮ → Delete. That unloads the platforms, closes every SignalR socket and drops the entry, its devices and its entities. The stored credentials go with it. Nothing is left behind on disk and nothing is changed on the Whisker account — the plug carries on reporting to Whisker Labs exactly as before. To remove the code as well, uninstall the repository in HACS and restart.
Via HACS. HACS → ⋮ → Custom repositories → https://github.com/jrackerby/whisker-ting,
category Integration. Install, restart Home Assistant, then add it under
Settings → Devices & Services → Add Integration → "Whisker Ting".
The integration lives at the repository root, not under
custom_components/. hacs.json declares content_in_root: true, so HACS
copies the root into /config/custom_components/whisker_ting/.
brand/ carries the Ting mark that Home Assistant and HACS show for this
integration. The directory name is brand, singular, and under
content_in_root: true it belongs at the repository root — HACS copies it
to custom_components/whisker_ting/brand/, which is the one path both
consumers read:
- Home Assistant core (2026.3.0+) gates on
"brand" inthe component's top-level files (loader.Integration.has_branding) and serves<component>/brand/<image>from/api/brands/integration/whisker_ting/, ahead ofbrands.home-assistant.io. No manifest key, no upstream PR. - HACS's
brandsvalidator looks for exactlybrand/icon.png— at the repo root whencontent_in_rootis set, under the content path otherwise — and only falls back to the brands repository when that file is absent.
Any other spelling (brands/, assets/, an icon.png at the root) fails
silently: nothing errors, HA serves the CDN placeholder, and the HACS
check reports the repository as missing from the brands repository rather
than as misfiled.
icon.png is 256×256 and icon@2x.png is 512×512, the sizes the brands
specification requires. logo*.png and the dark_* variants are omitted on
purpose: core's own fallback chain resolves each of them back to icon.png,
and the mark reads correctly on a light and a dark ground alike.
Issues and feature requests: jrackerby/whisker-ting/issues.
quality_scale.yaml is this integration's gap list against the
HA integration quality scale —
every rule marked done, todo or exempt with its reason. The manifest declares
no tier, deliberately (jrackerby/HA LAW §15). Silver is the target and is not
met yet; the open todos are tracked as issues.
CI runs hassfest
and HACS validation on every push, plus a check that quality_scale.yaml's
rows still match the rule list in home-assistant/core. validate.yml stages
the repo into the layout hassfest scans (jrackerby/HA tools/work_docs/TOOLS.md
carries why); the repo itself stays root-layout because hacs.json declares
content_in_root: true.
Pushing a manifest.json whose version has changed tags and publishes a
release automatically — that is the only supported way to cut one.