sense-node
v2.0.0
Published
Unofficial Node client for the Sense home energy monitor — realtime watts, trends, devices, with MFA/TOTP auth and token refresh.
Maintainers
Readme
sense-node
Unofficial Node client for the Sense home energy monitor —
the same api.sense.com REST API and clientrt.sense.com realtime websocket the
Sense apps use.
- ⚡ Realtime power — total watts, per-device watts, voltage, solar.
- 📈 Trends — day/week/month/year/billing-cycle usage history.
- 🔐 MFA/TOTP auth — finish 2FA manually, or auto-generate codes from a secret.
- ♻️ Token refresh — renews the access token automatically on expiry.
- 🪶 One dependency (
ws); nativefetchotherwise. Node ≥ 18.
⚠️ Unofficial and unsupported by Sense. Uses undocumented endpoints that can change without notice. Sense rate-limits the realtime websocket — sample a few frames and close (this library does that for you); don't hold it open.
Install
npm install sense-nodeQuick start (library)
const Sense = require('sense-node')
const sense = new Sense({ email: '[email protected]', password: 'secret' })
// Auth once — tokens cache to ~/.sense-node/state.json and refresh on expiry.
try {
await sense.authenticate()
} catch (e) {
if (e.name === 'SenseMFARequiredError') {
await sense.validateMFA('123456') // code from your authenticator app
} else throw e
}
// Realtime snapshot (samples a few frames, then closes the socket):
console.log(await sense.getRealtime())
// → { watts: 1148, voltage: [120, 120.1], hz: 60, solarWatts: 0,
// devices: [ { name: 'AC', watts: 900 }, { name: 'Fridge', watts: 120 }, … ],
// raw: { … } }
// Trends:
console.log(await sense.getTrends('DAY')) // DAY | WEEK | MONTH | YEAR | CYCLEAutomatic MFA (headless / cron)
Pass the base32 TOTP secret (shown when you set up 2FA — not a 6-digit code) and the client generates and submits codes itself:
const sense = new Sense({ email, password, mfaSecret: 'JBSWY3DPEHPK3PXP' })
await sense.authenticate() // handles MFA with no interactionQuick start (CLI)
export [email protected] SENSE_PASSWORD=secret
# optional: export SENSE_MFA_SECRET=JBSWY3DPEHPK3PXP (base32, for auto-MFA)
sense auth # authenticate (or: sense auth mfa <code>)
sense now # ⚡ 1148W now — AC 900W, Fridge 120W, …
sense now --json # full realtime snapshot
sense trends WEEK # usage history
sense devices # discovered devices
sense status # cached auth stateCLI env vars: SENSE_EMAIL, SENSE_PASSWORD, SENSE_MFA_SECRET, SENSE_STATE
(token-file path), SENSE_VERBOSE=1.
API
| Method | Returns | Notes |
| --- | --- | --- |
| new Sense({ email, password, mfaSecret?, statePath?, tokenStore?, verbose? }) | — | state defaults to ~/.sense-node/state.json |
| authenticate(email?, password?) | true | throws SenseMFARequiredError if 2FA needed and no mfaSecret |
| validateMFA(code) | true | complete 2FA after the error above |
| renewAuth() | true | refresh the access token (done automatically on 401/403) |
| isAuthorized() | boolean | |
| getRealtime({ samples?, timeoutMs? }) | snapshot | watts, voltage, hz, solarWatts, devices[] |
| getTrends(scale?, start?) | object | scale: DAY/WEEK/MONTH/YEAR/CYCLE |
| getDevices() / getMonitorOverview() / getMonitorStatus() | object | |
| getDailyUsage(scale?, start?) | object | back-compat: trends + live currentConsumption |
Custom token storage
Pass any object with get(key) / set(key, value) as tokenStore to keep tokens
somewhere other than a file (DB, secrets manager, etc.).
Migrating from v1
axios+momentare gone (nativefetch+Date); onlywsremains.- The trends endpoint moved to
app/monitors/{id}/history/usage—getTrends()uses it.getDailyUsage(scale, start)is kept for compatibility. - New:
mfaSecret/validateMFA(MFA didn't exist in v1),renewAuth, a cached token store, and asenseCLI.
License
MIT © Noel Portugal
