meross-iot
v0.9.1
Published
Control Meross cloud devices using nodejs
Maintainers
Readme
MerossIot
A Node.js library for controlling Meross cloud devices. This library allows you to login into Meross cloud server, read registered devices, and open connections to the MQTT cloud server to get device data.
This code tries to closely mirror the MerossIot Python project to provide a similar API and functionality for Node.js. This library was created for use in creating a Meross integration for the Homey smart home platform.
The library can control devices locally via HTTP or via cloud MQTT server.
Requirements
- Node.js >= 18
Installation
⚠️ Pre-release: This is currently an unstable pre-release. Use with caution.
# Install alpha version
npm install meross-iot@alpha
# Or install specific version
npm install [email protected]Usage & Documentation
Refer to the example/README.md for detailed usage instructions, or simply have a look at the /example directory.
If you are really impatient to use this library, refer to the following snippet of code that looks for a device and turns it on/off.
const { ManagerMeross, MerossHttpClient } = require('meross-iot');
(async () => {
// Create HTTP client using factory method
const httpClient = await MerossHttpClient.fromUserPassword({
email: '[email protected]',
password: 'yourpassword'
});
// Create manager with HTTP client
const meross = new ManagerMeross({
httpClient: httpClient
});
// Listen for device events
meross.on('deviceInitialized', (deviceId, device) => {
console.log(`Device found: ${device.name} (${device.deviceType})`);
});
// Connect and discover devices
await meross.connect();
// Find a device and control it
const devices = meross.devices.list();
if (devices.length > 0) {
const device = devices[0];
// Example: Toggle a switch
if (device.toggle) {
await device.toggle.set({ channel: 0, on: true }); // Turn on channel 0
}
}
})();The example/ directory contains focused examples for different use cases:
basic-usage.js- Simple connection and device discoverydevice-control.js- Controlling switches, lights, and monitoring devicesevent-handling.js- Handling events from devices and the managersubscription-manager.js- Automatic polling and unified update streams with ManagerSubscriptiontoken-reuse.js- Saving and reusing authentication tokensstatistics.js- Enabling and viewing API call statisticserror-handling.js- Comprehensive error handling and MFAhub-devices.js- Working with hub devices and subdevicestransport-modes.js- Understanding different transport modesmultiple-accounts.js- Using multiple Meross accounts simultaneouslyfactory-pattern-usage.js- Recommended factory pattern for creating HTTP clients and managerstimer-usage.js- Creating and managing device timersselective-initialization.js- Selectively initializing devices and subdevices
Adding and Removing Devices
You can dynamically add and remove devices from the manager after initialization:
// Add a single device
const device = await manager.devices.initializeDevice('device-uuid');
// Add a subdevice (hub will be auto-initialized if needed)
const subdevice = await manager.devices.initializeDevice({
hubUuid: 'hub-uuid',
id: 'subdevice-id'
});
// Remove a device
const removed = await manager.devices.remove('device-uuid');
// Remove a subdevice
const removed = await manager.devices.remove({
hubUuid: 'hub-uuid',
id: 'subdevice-id'
});When removing a hub device, all its subdevices are automatically removed as well.
API Organization
The library follows a modular architecture with specialized managers for different concerns:
manager.devices- Device discovery, initialization, and lifecycle managementmanager.mqtt- MQTT connection management and message publishingmanager.http- LAN HTTP communication with devicesmanager.transport- Transport mode selection and message routingmanager.subscription- Automatic polling and unified update streams
This organization makes the API more discoverable and easier to use. For example:
// Discover devices without initializing
const availableDevices = await manager.devices.discover({ onlineOnly: true });
// Initialize devices
const count = await manager.devices.initialize();
// Encode and send a message via MQTT
const data = manager.mqtt.encode('GET', 'Appliance.Control.ToggleX', {}, device.uuid);
manager.mqtt.send(device, data);
// Send a message via LAN HTTP
await manager.http.send(device, '192.168.1.100', data);
// Use transport manager for automatic routing
await manager.transport.request(device, '192.168.1.100', data);Supported Devices
This library should support al wifi based devices Meross currently has on the market. I've tested the code with the following devices:
- MSS315 Smart Wi-Fi Plug Mini
- MSP844 Smart Fast Charging Power Strip
- MS130H Smart Temperature and Humidity Sensor Kit
- MS600 Smart Presence Sensor
- MOP320MA Smart Outdoor Plug with Energy Monitor
- MSS815MA Smart in-Wall Switch
- MSS715MA Smart DIY Switch with Energy Monitor
- MTS215MA Smart Thermostat
- MA151H Smart Smoke Alarm
- MSH450 Smart Hub
- MSH400HK Smart Hub
- MSH300HK Smart Hub
- MSL120HK Smart LED Light Bulb Pro
- MSL100HK Smart LED Light Bulb
- MS400H Smart Water Leak Sensor
Unsupported Device?
If your device is not supported or you're experiencing issues with a specific device, you may ask the developers to add specific support for that device. To do so, you will need to "sniff" low-level communication between your Meross App and the specific device. Such data can help the developers to add support for that device.
Please create an issue on GitHub and include:
- Device model name/number
- Device type
- Any error messages or unexpected behavior
- Sniffed device data (if available)
Changelog
[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
runtimeIntervaloption (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
- Added
[0.8.0] - 2026-01-22
Added
- Device initialization tracking with
deviceInitializedevent andready()method- Device emits
deviceInitializedevent after receiving System.All data device.ready()returns a promise that resolves when device is fully initialized- Initialization timeout detection with
MerossErrorInitializationerror
- Device emits
- 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 durationalarm.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.DNDModenamespace (was incorrectly usingAppliance.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
deviceStateIntervalfrom 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
- Changed default
Added
- Added
pushNotificationReceivedevent 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
DeviceCapabilitiesinterface
[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.)
- Converted all device methods to feature-based API (
- 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 consistencyAuthenticationError→MerossErrorAuthenticationConnectionError→MerossErrorConnectionDeviceError→MerossErrorDeviceHttpError→MerossErrorHttpMqttError→MerossErrorMqttNetworkError→MerossErrorNetworkProtocolError→MerossErrorProtocolTimeoutError→MerossErrorTimeoutTokenError→MerossErrorTokenValidationError→MerossErrorValidation
- All error classes now include
code,isOperational, andcauseproperties - 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
- Renamed all error classes to use
- 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
- Manager methods are now accessed via manager properties instead of direct methods:
Added
- Enhanced error context through error chaining via
causeproperty - 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()toinitializeDevices()inManagerMeross- The method name better reflects that it performs full device discovery, initialization, and connection setup, not just retrieval
- Updated
login()andconnect()to useinitializeDevices() - Updated all examples and TypeScript definitions
- BREAKING: Simplified device API by establishing single source of truth
- Removed
deviceDefparameter fromdeviceInitializedevent - now just(deviceId, device) - Removed
cachedHttpInfoproperty; all properties are now directly accessible onMerossDevice - 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
- Removed
- BREAKING: Removed snake_case handling, standardized on camelCase
- Removed snake_case property mappings from
HttpDeviceInfo,HttpSubdeviceInfo,HardwareInfo,FirmwareInfo, andTimeInfo - Updated filter parameters to camelCase (
deviceUuids,deviceType,onlineStatus, etc.) - Changed
subdevice_idgetter tosubdeviceIdin push notification classes - Updated
TokenDatainterface:issued_on→issuedOn - All JSDoc comments now reflect direct camelCase acceptance
- Removed snake_case property mappings from
Updated
- Updated all examples to use camelCase consistently
- Updated all examples to use
initializeDevices()instead ofgetDevices()
[0.3.1] - 2026-01-15
Fixed
- Fixed
ManagerSubscriptionconstructor bug: now properly callssuper()before accessingthisto 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 - usemeross.subscriptionproperty instead - Removed wrapper methods - use
meross.devices.*instead:getDevice(uuid)→meross.devices.get(uuid)findDevices(filters)→meross.devices.find(filters)getAllDevices()→meross.devices.list()
- Removed
- BREAKING: Unified device lookup API in DeviceRegistry
- Removed
lookupByUuid()andlookupByInternalId()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' })
- Base devices:
- Removed
- 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.subscriptionreturnsManagerSubscriptioninstance - Property access to device registry:
meross.devicesreturnsDeviceRegistryinstance with full API access - Unified
get()method in DeviceRegistry supporting both base devices and subdevices - Constructor option
subscriptionfor configuring subscription manager during initialization
[0.2.1] - 2026-01-14
Fixed
- Fixed syntax error in
device-control.jsexample - missing closing brace fordeviceInitializedevent handler
[0.2.0] - 2026-01-14
Changed
- BREAKING:
SubscriptionManagernow uses EventEmitter pattern instead of callbackssubscribe(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)andon('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.jsexample 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.
Disclaimer
All product and company names or logos are trademarks™ or registered® trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them or any associated subsidiaries! This personal project is maintained in spare time and has no business goal. MEROSS is a trademark of Chengdu Meross Technology Co., Ltd.
