@mega-yfue/eufy-sdk / EufyMegaEventMap
Type Alias: EufyMegaEventMap
type EufyMegaEventMap = { [K in keyof DeviceEventMap]: [DeviceEventMap[K]] } & object;The complete typed event surface of EufyMega — event name → listener-argument tuple.
Two groups:
- Semantic events (motion, doorbellPress, lockState, ptzNotify, …) — projected from the capability modules via DeviceEventMap, so adding a capability event adds a typed event here automatically (one line in that map).
- Low-level / lifecycle events — the raw escape hatches and transport lifecycle.
Type Declaration
availability
availability: [AvailabilityObservation];A verified vendor-wire availability observation. Duplicate states are coalesced; silence, lastSeenMs, operation failure and transport lifecycle never emit or clear this event.
commandAck
commandAck: [object];A transport-level command got an acknowledgement (or didn't) — emitted by the MQTT command router. For ff09-actuate the reply is a "device received it" signal, not a physical-actuation-complete one (see that handler's doc); for ff09-autolock the GET step already threw on no reply by the time this fires — getAcked is always true here, acked reports the SET step's fire-and-forget ack. dispatch()/lock()/unlock()/setAutoLock() stay Promise<void> and never throw on a missing SET ack (fire-and-forget, same as every other write) — this event is the optional channel for delivery visibility, without the dispatch contract itself changing shape. Secure-MQTT DP writes use the persistent account connection and report broker publication (acked: true) without an instanceIp; that is not device convergence.
commandUnconfirmed
commandUnconfirmed: [object];A write was acknowledged and its declared observation then never converged, so the device never reported the state the write asked for.
This is the answer to the question dispatch deliberately does not wait for. A command resolves once the transport has carried it, and the observation a member declares decides separately whether the device applied it; where that observation times out, the wire accepted the write and the device ignored it — seen on a battery camera whose power write is acknowledged and never acted on. It is reported here rather than on error because it is an outcome and not a fault, for the same reason commandAck has its own channel. observed is what the param read when the deadline passed, absent where the device reported none at all.
connect
connect: [];deviceAdded
deviceAdded: [EufyDevice];A device appeared on the account since the previous poll — a pairing, or a device that became visible again. Account topology, so it lives here rather than on the per-device capability map.
Fires only for a device the SDK has seen the account WITHOUT; the first enumeration after login is not a stream of additions. Suppressed when the baseline it would be measured against only partly resolved, so a recovering outage doesn't read as a burst of pairings.
deviceCapabilities
deviceCapabilities: [object];A device a caller is holding gained capabilities, because it reported evidence it hadn't before. gained is what is newly available; capabilities is the full set after widening.
A Device resolves its capabilities from the evidence available at the time, so one resolved before the device had reported a param lacks the capability that param proves. When a later poll supplies it, the object is re-resolved and re-bound in place — the new accessor is live on the instance the host already has. Capabilities are never retracted, so this only ever widens.
deviceRemoved
deviceRemoved: [EufyDevice];A device is gone from the account — unpaired, or moved away.
Deliberately conservative: suppressed when a poll only partially resolved (a failed house query returns a subset), because an absence caused by an outage is not a removal.
deviceState
deviceState: [DeviceState];A device reported to the cloud since the last poll — its DeviceState.lastSeenMs advanced. Carries DeviceState; the host applies its own staleness threshold.
Transport/session lifecycle is NOT this event: that's p2pConnect/p2pClose, station-scoped where a session actually lives.
disconnect
disconnect: [unknown];error
error: [Error];event
event: [AnyDeviceEvent];Catch-all: fires for EVERY semantic event, payload tagged with its eventName.
map
map: [object];A device's map changed — a new cell plane, a renamed room, a zone the user drew.
Carries the whole snapshot rather than the piece that changed, because the pieces are only useful together: a room outline without the room list names nothing. Emitted only when something actually changed; the robot republishes its map throughout a clean and a repeat of what is already held is dropped rather than woken on.
mapFrame
mapFrame: [object];One frame off a clean-line device's map stream — the biz/…/res leg, which carries pixel planes, room outlines and names, virtual walls and the live pose.
The frame is unwrapped as far as its bytes and no further: frame.payload is a Raw-DP frame in the base64 a codec reads, and frame.channelId says which stream.proto message it holds. That split is deliberate while the decoders are being built — the meaning of a channel is settled in one place rather than in this event's shape.
message
message: [RealtimeMessage];p2p
p2p: [P2PFrame];p2pClose
p2pClose: [string];p2pConnect
p2pConnect: [string];p2pLevel2Ready
p2pLevel2Ready: [object];push
push: [PushEvent];pushConnect
pushConnect: [];pushDisconnect
pushDisconnect: [];pushRaw
pushRaw: [RawPushMessage];sessionExpired
sessionExpired: [Error];The cloud session was kicked or invalidated — another client logged into the same account, or the token expired. The SDK has already cleared the persisted session, so recovery is a fresh login() (which usually needs 2FA). Distinct from error: a session error is emitted ONLY here, not also on error.