# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.10.0] - 2026-05-19

### Added
- `Meross.authenticate()` — authenticate and return a manager without connecting to the cloud or initializing devices
- `Meross.connect()` — static entry point that authenticates and connects in one step
- Multi-channel helpers on toggle, timer, and trigger abilities: `getAll()` aggregates state across all device channels; timer and trigger also expose `count()`
- `getDeviceChannelIds()` utility for consistent channel enumeration from capabilities or device metadata
- Namespace dispatcher with header-timestamp ordering gate for SETACK, GETACK, and PUSH state updates
- Shared cache helpers (`readCache`, `getCachedOrFetch`) used by ability `get()` methods
- Unit test suite (198 tests) covering abilities, dispatcher, push notifications, authentication, and public module surface
- `manager.mqtt.connections` — exposes active MQTT connection map for diagnostics

### Changed
- **BREAKING**: Renamed `ManagerMeross` to `Meross` (default export)
  - `const Meross = require('meross-iot')` replaces `const ManagerMeross = require('meross-iot')`
  - Direct construction requires an authenticated HTTP client; use `Meross.authenticate()` or `Meross.connect()` as entry points
- **BREAKING**: Removed public `MerossHttpClient` export
  - Use `Meross.authenticate()` for credential exchange and token reuse via `meross.getTokenData()`
- **BREAKING**: Consolidated error classes into a smaller hierarchy with string `code` discriminators
  - Exported: `MerossError`, `MerossAuthError`, `MerossDeviceError`, `MerossApiError`, `MerossNetworkError`
  - Removed granular exports such as `MerossErrorAuthentication`, `MerossErrorTokenExpired`, `MerossErrorCommandTimeout`, `MerossErrorValidation`, etc.
  - Catch category errors with `instanceof` and inspect `error.code` for specific handling (e.g. `TOKEN_EXPIRED`, `VALIDATION_ERROR`, `COMMAND_TIMEOUT`)
  - Removed public `mapErrorCodeToError` export
- **BREAKING**: Renamed `device.getUnifiedState()` to `device.getState()`
  - State is now derived from dispatcher namespace descriptors rather than hand-maintained aggregation
- **BREAKING**: Unified device initialization events
  - Device emits `ready` (replacing `deviceInitialized`); manager emits `deviceReady` when a device finishes bootstrap
  - `device.ready()` promise API unchanged
- **BREAKING**: Device abilities are initialized conditionally based on supported namespaces
  - Unsupported features are absent (`undefined`) rather than present with stub methods
- **BREAKING**: Transport and statistics are accessed exclusively via sub-managers
  - Use `meross.transport` for mode selection, error budgets, and request queuing
  - Use `meross.statistics` for HTTP/MQTT stats (`enable()`, `getHttpStats()`, `getMqttStats()`)
- **BREAKING**: Trimmed public module exports to documented API surface
  - Removed exports for state classes, push notification classes, `TimerUtils`, `TriggerUtils`, `createDebugUtils`, `ManagerSubscription`, and `MerossHttpClient`
  - Removed `ThermostatWorkingMode` and `ThermostatModeBState` from package root exports (still available internally)
- **BREAKING**: Internal package layout restructured (no import-path stability for deep requires)
  - `lib/controller/features/` → `lib/abilities/`
  - `lib/managers/` → `manager/`
  - `lib/controller/` → `lib/device/`
  - `lib/http-api.js` → `lib/api/client.js`
- Subdevice state updates now pass through the same ordering gate as base devices, preventing stale hub sensor payloads from overwriting fresher per-namespace data
- Rewrote TypeScript definitions to match the simplified public API
- Updated all examples for the new connect/authenticate flow and ability-based device control

### Fixed
- Rewrote `publishMessage` without an async Promise executor
- HTTP API status errors are routed through `mapErrorCodeToError` consistently
- Exposed `manager.mqtt.connections` and aligned `disconnectAll()` routing through the mqtt getter

### Removed
- Standalone `lib/error-budget.js` (error budget logic lives on `ManagerTransport`)
- `lib/utilities/debug.js` and `createDebugUtils` export
- Internal ability `_update*` test hooks; state is exercised through dispatcher shims in tests

## [0.9.1] - 2026-01-22

### Fixed
- Improve heartbeat offline detection by using response silence (≥ heartbeat interval) instead of treating individual command errors/timeouts as offline signals

## [0.9.0] - 2026-01-22

### Added
- Signal strength property (`device.signalStrength`) from Appliance.System.Runtime
  - Provides signal strength percentage (1-100) on production firmware
  - Automatically updated when runtime data is fetched
  - Available in TypeScript definitions
- Runtime polling support in ManagerSubscription
  - Added `runtimeInterval` option (default: 60000ms) for periodic runtime data polling
  - Runtime data (signal strength, network type, IoT status) requires polling as it doesn't support push notifications
  - Respects smart caching configuration to reduce network traffic
  - Polling automatically skips when device is offline

## [0.8.0] - 2026-01-22

### Added
- Device initialization tracking with `deviceInitialized` event and `ready()` method
  - Device emits `deviceInitialized` event after receiving System.All data
  - `device.ready()` returns a promise that resolves when device is fully initialized
  - Initialization timeout detection with `MerossErrorInitialization` error
- Heartbeat monitoring utility for online/offline detection
  - Periodic heartbeat checks to monitor device connectivity
  - Tracks command responses and failures to detect connectivity issues
  - Updates device online status when connectivity problems are detected
  - Uses exponential backoff when device is offline
- Alarm control methods for alarm devices (e.g., MSH450 Internal Siren)
  - `alarm.set()` method to control alarm on/off state with optional duration
  - `alarm.setConfig()` method to configure alarm volume, tone, and enable state
  - Updated TypeScript definitions for new alarm methods
- Additional device property tracking
  - Track chipType, homekitVersion, wifi info, network stats
  - Extract network properties from System.Debug responses (RSSI, signal, SSID, channel, SNR, etc.)
  - Property update logic moved to system feature module

### Changed
- Moved System.All handling to system feature module
  - System.All property extraction logic moved from device.js to system feature
  - System feature handles hardware, firmware, and network property updates
  - Device delegates System.All updates to system feature module
- Skip polling for offline devices in subscription manager
  - Polling methods check online status before making requests
  - Avoids API calls when devices are known to be offline

### Fixed
- DND capability check now uses `Appliance.System.DNDMode` namespace (was incorrectly using `Appliance.Control.DNDMode`)
- Prevent redundant ability updates when abilities haven't changed
- Device initialization event now properly emitted by device itself after System.All is received

## [0.7.2] - 2026-01-21

### Changed
- Optimized ManagerSubscription polling behavior for better efficiency
  - Changed default `deviceStateInterval` from 30000ms to 0 (push-only by default after initial state)
  - Device state is now polled once on initial subscription to establish baseline, then relies on push notifications
  - Implemented per-namespace push tracking instead of global push active state for more granular control
  - Removed unnecessary push-active checks from electricity/consumption polling (these features don't support push notifications)
  - Polling now skips when recent push notifications were received for the specific namespace being polled

### Added
- Added `pushNotificationReceived` event to MerossDevice that emits the namespace for push activity tracking
  - Allows subscription manager to track push notifications per-namespace for selective polling optimization

### Fixed
- Removed default channel initialization for subdevices that could cause incorrect channel setup

## [0.7.1] - 2026-01-21

### Fixed
- Prefer Consumption/ConsumptionX/ConsumptionH in the right order and fallback sequence when fetching usage history
- Poll electricity via the feature-based API and honor channel cache data in ManagerSubscription

## [0.7.0] - 2026-01-20

### Added
- Normalized device capabilities map (`device.capabilities`)
  - Provides user-friendly capability discovery without needing to know Meross namespace strings
  - Includes channel information and feature-specific capabilities (toggle, light, thermostat, etc.)
  - Each feature now exports `getCapabilities()` function to provide capability information
  - Capabilities are automatically built when device abilities are updated
  - TypeScript definitions updated with `DeviceCapabilities` interface

## [0.6.0] - 2026-01-20

### Changed
- **BREAKING**: Migrated to feature-based API architecture
  - Converted all device methods to feature-based API (`device.feature.method()`)
  - Replaced direct feature imports with factory functions
  - Standardized `get()`/`set()` methods across all 27 features
  - Updated all test files to use new API
  - Updated TypeScript definitions for new API structure
  - Added system device tests (`test-system.js`)
  - Breaking changes include:
    - `device.setLightColor()` → `device.light.set()`
    - `device.getLightState()` → `device.light.get()`
    - Similar changes for all features (toggle, thermostat, etc.)
- Standardized error naming in JSDoc comments to use MerossError* convention
  - Replace shortened error names (HttpApiError, TokenExpiredError, etc.) with full MerossError* names
  - Replace generic {Error} references with specific MerossError* classes where appropriate
  - Fix incorrect import paths in feature files to use MerossError* naming
  - Update all @throws annotations to consistently use MerossError* naming convention

### Added
- System device tests (`test-system.js`)

## [0.5.0] - 2026-01-19

### Changed
- **BREAKING**: Standardized error handling with MerossError* naming convention
  - Renamed all error classes to use `MerossError*` prefix for consistency
    - `AuthenticationError` → `MerossErrorAuthentication`
    - `ConnectionError` → `MerossErrorConnection`
    - `DeviceError` → `MerossErrorDevice`
    - `HttpError` → `MerossErrorHttp`
    - `MqttError` → `MerossErrorMqtt`
    - `NetworkError` → `MerossErrorNetwork`
    - `ProtocolError` → `MerossErrorProtocol`
    - `TimeoutError` → `MerossErrorTimeout`
    - `TokenError` → `MerossErrorToken`
    - `ValidationError` → `MerossErrorValidation`
  - All error classes now include `code`, `isOperational`, and `cause` properties
  - Added `toJSON()` method to all error classes for serialization
  - Updated TypeScript definitions to match new error structure
  - Updated error-handling example to use new error class names
- **BREAKING**: Split ManagerMeross into separate lazy-loaded manager modules
  - Manager methods are now accessed via manager properties instead of direct methods:
    - `manager.devices` - device discovery and initialization (ManagerDevices)
    - `manager.mqtt` - MQTT connection management (ManagerMqtt)
    - `manager.http` - LAN HTTP communication (ManagerHttp)
    - `manager.transport` - transport mode selection and routing (ManagerTransport)
    - `manager.statistics` - statistics tracking (ManagerStatistics)
    - `manager.subscription` - device update subscriptions (ManagerSubscription)
  - Extracted DeviceRegistry to standalone module
  - Moved subscription manager to `managers/` directory
  - Updated all examples and TypeScript definitions for new API

### Added
- Enhanced error context through error chaining via `cause` property
- Error serialization support via `toJSON()` method on all error classes
- Lazy-loaded manager modules for better code organization and performance

## [0.4.0] - 2026-01-16

### Changed
- **BREAKING**: Renamed `getDevices()` to `initializeDevices()` in `ManagerMeross`
  - The method name better reflects that it performs full device discovery, initialization, and connection setup, not just retrieval
  - Updated `login()` and `connect()` to use `initializeDevices()`
  - Updated all examples and TypeScript definitions
- **BREAKING**: Simplified device API by establishing single source of truth
  - Removed `deviceDef` parameter from `deviceInitialized` event - now just `(deviceId, device)`
  - Removed `cachedHttpInfo` property; all properties are now directly accessible on `MerossDevice`
  - Converted simple getters to direct properties (`macAddress`, `lanIp`, `mqttHost`, etc.)
  - Updated all feature files to use public properties (`abilities`, `lastFullUpdateTimestamp`)
  - Removed unnecessary defensive fallback patterns (`device.dev?.uuid` → `device.uuid`)
  - Fixed subdevice property consistency
- **BREAKING**: Removed snake_case handling, standardized on camelCase
  - Removed snake_case property mappings from `HttpDeviceInfo`, `HttpSubdeviceInfo`, `HardwareInfo`, `FirmwareInfo`, and `TimeInfo`
  - Updated filter parameters to camelCase (`deviceUuids`, `deviceType`, `onlineStatus`, etc.)
  - Changed `subdevice_id` getter to `subdeviceId` in push notification classes
  - Updated `TokenData` interface: `issued_on` → `issuedOn`
  - All JSDoc comments now reflect direct camelCase acceptance

### Updated
- Updated all examples to use camelCase consistently
- Updated all examples to use `initializeDevices()` instead of `getDevices()`

## [0.3.1] - 2026-01-15

### Fixed
- Fixed `ManagerSubscription` constructor bug: now properly calls `super()` before accessing `this` to correctly initialize EventEmitter parent class

## [0.3.0] - 2026-01-15

### Changed
- **BREAKING**: Renamed core classes to follow Manager-prefix naming pattern
  - `MerossManager` → `ManagerMeross` (all imports/exports)
  - `SubscriptionManager` → `ManagerSubscription` (all imports/exports)
- **BREAKING**: Replaced method-based access with property-based access patterns
  - Removed `getSubscriptionManager()` method - use `meross.subscription` property instead
  - Removed wrapper methods - use `meross.devices.*` instead:
    - `getDevice(uuid)` → `meross.devices.get(uuid)`
    - `findDevices(filters)` → `meross.devices.find(filters)`
    - `getAllDevices()` → `meross.devices.list()`
- **BREAKING**: Unified device lookup API in DeviceRegistry
  - Removed `lookupByUuid()` and `lookupByInternalId()` from public API
  - Added unified `get(identifier)` method that handles both base devices and subdevices:
    - Base devices: `meross.devices.get('device-uuid')`
    - Subdevices: `meross.devices.get({ hubUuid: 'hub-uuid', id: 'subdevice-id' })`
- **BREAKING**: Renamed DeviceRegistry methods for cleaner API
  - `getAllDevices()` → `list()` (returns all devices)
  - `findDevices(filters)` → `find(filters)` (search/filter devices)

### Added
- Property access to subscription manager: `meross.subscription` returns `ManagerSubscription` instance
- Property access to device registry: `meross.devices` returns `DeviceRegistry` instance with full API access
- Unified `get()` method in DeviceRegistry supporting both base devices and subdevices
- Constructor option `subscription` for configuring subscription manager during initialization

## [0.2.1] - 2026-01-14

### Fixed
- Fixed syntax error in `example/device-control.js` - missing closing brace for `deviceInitialized` event handler

## [0.2.0] - 2026-01-14

### Changed
- **BREAKING**: `SubscriptionManager` now uses EventEmitter pattern instead of callbacks
  - `subscribe(device, config, onUpdate)` → `subscribe(device, config)` (no callback, no return value)
  - `unsubscribe(deviceUuid, subscriptionId)` → `unsubscribe(deviceUuid)` (no subscription ID needed)
  - `subscribeToDeviceList(onUpdate)` → `subscribeToDeviceList()` (no callback, no return value)
  - `unsubscribeFromDeviceList(subscriptionId)` → `unsubscribeFromDeviceList()` (no subscription ID needed)
  - Listen for updates using: `on('deviceUpdate:${deviceUuid}', handler)` and `on('deviceListUpdate', handler)`
  - Use standard EventEmitter methods: `on()`, `once()`, `off()`, `removeAllListeners()`
  - Configuration is now per-device subscription (merged aggressively) rather than per-listener

### Added
- `subscription-manager.js` example demonstrating EventEmitter-based SubscriptionManager usage
- Enhanced documentation for SubscriptionManager with JSDoc comments explaining implementation rationale

## [0.1.0] - 2026-01-10

### Added
- Initial release of MerossIot Node.js library
- Meross Cloud authentication and token management
- Device discovery and enumeration
- MQTT cloud server connection support
- HTTP local device control support
- Support for various device types (switches, lights, sensors, etc.)
- Hub device and subdevice support
- Event handling for device updates and state changes
- Error handling with comprehensive error types
- Statistics tracking for API calls
- Command-line interface (CLI) for testing and debugging
- TypeScript type definitions
- Examples in the `example/` directory

### Known Issues
- This is an initial, pre-stable release. Please expect bugs. 
- Some edge cases may not be fully handled yet.

