0.3.3 • Published 12 days ago

node-mideahvac v0.3.3

Weekly downloads
25
License
MIT
Repository
github
Last release
12 days ago

Monitoring and controlling Midea-like air conditioners

Build Coverage Status npm

Note: Version 0.2.0 is a complete rewrite and not backwards compatible. The midea cloud is no longer supported, instead direct communication (over the LAN) to the airconditioner using the original SmartKey dongle is supported.

This module enables the monitoring and controlling of 'Midea'-like airconditioners. The remote control functionality via WiFi provided by various vendors of air conditioners, either as default or optional feature, is using the same type of interface and the Midea cloud. Examples of vendors using this interface are:

  • Midea
  • Qlima
  • Artel
  • Carrier

The WiFi interface is provided by a dongle, called WiFi SmartKey (sk103), either connected to an USB type-A connector or a JST-HX type of connector. This dongle wraps the UART protocol used to communicate with the AC unit with a layer for authentication and encryption for communication with a mobile app via the Midea cloud or directly via a local LAN connection. However, it turned out the dongle is just connected to a serial interface (TTL level) of the AC unit. This means an alternative is to hook up directly to this serial interface and bypass the cloud, authentication and encryption stuff. More information on creating a custom dongle can be found the prerequisites section.

This module supports direct communication using the WiFi SmartKey and direct communication via a TCP-serial bridge connected to the UART port of the appliance (e.g a custom dongle running esp-link firmware).

References and sources

The knowledge to create the logic to monitor and control the Midea-'like' AC units was gathered by reverse engineering Android applications from various vendors, analyzing the UART protocol between an Artel unit and an SK103 SmartKey, documents found on the Internet, primarily in Chinese and the work from:

Mac Zhou and Nenad Bogojevic deserve all the credits for reverse engineering the direct communication with the SmartKey. Where I had given up on ever figuring out how to obtain the key and token required, Mac persisted and eventually was successful, while Nenad was able to discover what changed in this process for users who migrated their accounts from the Midea Air app to the SmartHome app.

Status

All common functions of Airconditioners are supported, but support for specific features only available on some airconditioners might be incomplete or missing because it is unknown how they work and the inability to test. Any help is welcome. Also support for (de)humidifiers is missing.

The direct communication with the original dongle, the SmartKey, has been tested with a SK103 running firmware 3.0.8. The discover command required to obtain the token and key required for direct communication only supports accounts that have been migrated to the SmartHome app.

:warning: The SK103 module, when using the SK103 communication method and poll the status frequently, might disconnect from your WiFi network and a powercycle is required to reconnect. Lowering the frequency of polling might prevent this.

Prerequisites

For the direct communication method using an SK103 original SmartKey dongle is required running firmware version 3.0.8 and a SmartHome account (Midea Air or NetHome Plus accounts do not work anymore because Midea removed the ability to retrieve the required key and token for these type of accounts).

For the serialbridge a custom dongle is required running the esp-link firmware). Examples of designs of custom dongles are:

Installation

npm install node-mideahvac

Usage

First create an appliance instance by specifying the following parameters:

parameterusemethod
communicationMethodthis must be either 'sk103' or 'serialbridge'sk103 / serialbridge
hostthis is the address of the dongle, either the SmartKey (sk103) or the custom dongle running TCP-serial bridge firmwaresk103 / serialbridge
portthis is the port the TCP-serial bridge firmware is listening on (default 23)serialbridge
idthe id of the appliance (as can be determined using the discovery tool)sk103
keyThe key can be obtained using the discover tool)sk103
tokenThe token can be obtained using the discover tool)sk103

For each AC unit to be monitored and controlled an appliance must be instantiated.

An example of creating an appliance using the sk103 direct communication method:

const appliances = require('node-mideahvac')

var options = {
    communicationMethod: 'sk103',
    id: <the id of the device to control>,
    key: <the key for the device to control>,
    token: <the token for the device to control>
}

var ac = appliances.createAppliance(options)

An example of creating an appliance using a TCP serial bridge:

const appliances = require('node-mideahvac')

var options = {
    communicationMethod: 'serialbridge',
    host: '192.168.10.34',
    port: 23
}

var ac = appliances.createAppliance(options)

Methods

All methods return a promise and the retry parameter indicates how many times the command must be retried when a retryable error occurs (default = 0).

The following methods are provided:

  • getCapabilities(retry), this method requests the AC unit for its supported capabilities (0xB5 query). This command is not supported by all AC units and the reported values are not always correct (e.g. my Artel units report the left/right fan can be controlled while it can only be manually controlled and Fahrenheit as unit is not supported while it is).

    The default values specify which value is reported by this module when the AC unit does not report this capability at all.

    The promise resolves to a JSON object containing the following capabilities:

CapabilityTypeDefaultDescription
activeCleanbooleanfalseactive cleaning mode
autoModebooleanfalseauto mode (cooling or heating is automatically selected)
autoSetHumiditybooleanfalsehumidity setpoint automatically determined
breezeControlbooleanfalsebreeze mode can be controlled
buzzerbooleanfalsebuzzer can be disabled
coolModebooleanfalsecooling mode
decimalsbooleanfalsesetpoint in decimals
downNoWindFeelbooleanfalse
dryModebooleanfalsedry mode
ecoModebooleanfalseeco mode
electricAuxHeatingbooleanfalse
fanSpeedControlbooleantruefan speed can be controlled
frostProtectionModebooleanfalsetemperature is maintained at 8C to protect against frost
heatModebooleanfalseheat mode
indoorHumiditybooleanfalseindoor humidity is reported
leftrightFanbooleanfalseleft/right fan can be controlled
lightControlbooleanfalsedisplay can be dimmed
manualSetHumiditybooleanfalsehumidity setpoint can be specified
maxTempAutonumber30maximum setpoint in auto mode
maxTempCoolnumber30maximum setpoint in cool mode
maxTempHeatnumber30maximum setpoint in heat mode
minTempAutonumber17minimum setpoint in auto mode
minTempCoolnumber17minimum setpoint in cool mode
minTempHeatnumber17minimum setpoint in heat mode
nestCheckbooleanfalse
nestNeedChangebooleanfalse
oneKeyNoWindOnMebooleanfalse
oneKeyNoWindOnMebooleanfalse
powerCalbooleanfalsepower usage can be reported
powerCalSettingbooleanfalse
silkyCoolbooleanfalse
smartEyebooleanfalse
specialEcobooleanfalse
turboCoolbooleanfalsecool mode supports turbo mode
turboHeatbooleanfalseheat mode supports turbo mode
unitChangeablebooleanfalsethe temperature unit can be changed from Celsius to Fahrenheit
updownFanbooleanfalseup/down fan can be controlled
upNoWindFeelbooleanfalse
windOffMebooleanfalse
windOnMebooleanfalse
  • getPowerUsage(retry), this method requests the current power usage of the unit (specific 0x41 command). The promise resolves to a JSON object containing the property values when successful. The following properties are reported:
PropertyTypeDescription
powerUsagenumberPower usage in kWh
  • getStatus(retry), this method requests the current status of the unit (0x41 command). The promise resolves to a JSON object containing the property values when successful. The following properties are reported:
PropertyValuesDescription
braceletControltrue/false
braceletSleeptrue/false
catchColdtrue/false
childSleeptrue/false
coolFantrue/false
cosySleep0: no sleep1: sleep 12: sleep 23: sleep 3sleep mode, reported as the following JSON object:{ value: n, description: text }
downWindControltrue/false
downWindControlLRtrue/false
dryCleantrue/false
dualControltrue/falseprobably to the follow me mode is active where the remote control acts as the temperature sensor
dustFulltrue/false
ecoModetrue/falseeco mode is enabled
ecoSleepRunningHours0-15
ecoSleepRunningMinutes0-59
ecoSleepRunningSeconds0-59
fanSpeed0-20: silent21-59: low60-79: medium80-100: high101: fixed102: autoreported as the following JSON object:{ value: n, description: text }
fastChecktrue/false
feelOwntrue/false
frostProtectiontrue/falsefrost protection is active
humiditySetpoint0-100%humidity setpoint
indoorTemperature-25-102°C-13-215°Findoor temprature
inErrortrue/falsethe unit is in error
keepWarmtrue/false
leftrightFantrue/falseleft/right fan is active
light0-7brightness level of display light
lowFrequencyFantrue/false
mode1: auto2: cool3: dry4: heat5: fanonly6: customdryreported as the following JSON object:{ value: n, description: text }
naturalFantrue/false
nightLighttrue/false
offTimertrue/falsescheduled to turn on
offTimerHours0 - 24number of hours until the unit will be turned off
offTimerMinutes0 - 59number of minutes until the unit will be turned off
onTimertrue/falsescheduled to turn on
onTimerHours0 - 24number of hours until the unit will be turned on
onTimerMinutes0 - 59number of minutes until the unit will be turned on
outdoorTemperature-25-102°C-13-215°Foutdoor temperature
peakValleyElectricitySavingtrue/false
pmv99: off-3: cold-2.5: chill-2: chill-1.5: cool-1: cool-0.5: comfortable0: comfortable0.5: comfortable1: slightly warm1.5: slightly warm2: warm 2.5: warmpredicted mean vote (the experienced temperature), reported as the following JSON object:{ value: n, description: text }
powerOntrue/falsepower status
ptcHeatertrue/false
purifytrue/false
resumetrue/falseautomatically resume after recovery from power failure
savetrue/false
selfCosySleeptrue/false
selfFeelOwntrue/false
sleepModetrue/falsesleep mode is activated
smartEyetrue/false
smartWindtrue/false
statusCodesee Status codesreported as the following JSON object:{ value: n, description: text }
temp0-32probably the temperature reported by the remote control sensor in follow me mode
tempDecimaltrue/falseprobably indicates decimals are supported for the temperature reported by the remote control
temperatureSetpoint17 - 30°C62-86°Ftemperature setpoint
temperatureUnit0: Celsius1: Fahrenheitunit used to report temperatures
timerMode0: relative1: absolutehow to specify the time for the timer (only relative mode is supported)
turboModetrue/falseturbo mode enabled
updownFantrue/falseup/down fan is active
ventilationtrue/false
windBlowingtrue/false

Properties with a name like bytenbitm can also be reported. These are properties where I do not have a clue whether they are used. For instance byte3bit3 means the value of bit 3 in byte 3, or byte3bit34 means the value of bit3-4 in byte 3. You would help me to determine the meaning of these bits when you report them in the issues section with their values and possibly what happened.

Status codes: | Code | Description | | --- | --- | | 0 | ok | | 1 | interior board and display board communication failure | | 2 | indoor main control board failure | | 3 | indoor board and outdoor board communication failure | | 4 | zero crossing detection failure | | 5 | indoor board fan stall failure | | 6 | outdoor condenser sensor failure | | 7 | outdoor ambient temperature sensor failure | | 8 | outdoor compression engine exhaust temperature sensor failure | | 9 | outdoor failure | | 10 | indoor temperature sensor failure | | 11 | indoor evaporator temperature sensor failure | | 12 | outdoor wind speed stall failure | | 13 | ipm module protection | | 14 | voltage protection | | 15 | outdoor compressor top temperature protection | | 16 | outdoor temperature too low protection | | 17 | compressor position protection | | 18 | display panel fault | | 21 | outer pipe temperature protection | | 23 | exhaust high temperature protection | | 25 | heating and cold wind protection | | 26 | current protection | | 29 | evaporator high and low temperature protection | | 30 | condenser high and low temperature protection frequency limit | | 31 | exhaust high and low temperature protection | | 32 | indoor and outdoor communication mismatch protocol | | 33 | refrigerant leakage protection | | 38 | water tank full or missing |

  • initialize(), this method can be used to perform some initializion:

    • The getCapabilities command is issued to determine the supported capabilities
    • The setStatus command is issued to determine the current values of all properties
    • The sendNetworkStatusNotification command (only when the serialbridge method is used) is scheduled to be issued every 2 minutes to make sure the WiFi connected symbol is show on the AC display. The response is a JSON object merging the responses from the getCapabilities and getStatus mthods.
  • sendNetworkStatusNotification(), this method is only available for the serialbridge communication method must be called at least once every 2 minutes in order to display the WiFi connected symbol in the display of the AC.

  • setStatus(properties, retry), this method must be used to change the status of the unit. The properties parameter is an object containing all the properties and their values that need to be changed. To prevent changing properties unintentionaly, before calling the setStatus command a getStatus command must be send to retrieve the current values of all properties. The response is a JSON object containing all the properties with their values, just like returned by the getStatus method.

The following properties can be set:

PropertyTypePossible valuesDescription
beepbooleantrue, falseen/disable a beep as feedback
fanSpeedstringnumbersilent, low, medium, high, auto or 0 - 100%set the fan speed
frostProtectionModebooleantrue, falseturn frost protection mode (min. temperature is 8°C) on/off. This is only supported in heat mode
humiditySetpointnumber35 - 85set the desired humidity in %
leftrightFanbooleantrue, falseturn the left/right (vertical) fan on/off
modestringcool, heat, fanonly, dry, auto, customdryset the operational mode
powerOnbooleantrue, falsepower the unit on/off
temperatureSetpointnumber16 - 31 / 60 - 87set the desired temperature in °C or °F
sleepModebooleantrue, falseturn the sleep mode on/off
temperatureUnitstringfahrenheit, celsiusset the temperature unit to fahrenheit/celsius
turboModebooleantrue, falseturn turbo mode on/off
updownFanbooleantrue, falseturn the up/down (horizontal) fan on/off

Example: Turn the unit on, set the temperature setpoint to 24°C and retry max. 3 times.

ac.setStatus({ powerOn: true, setpoint: 24 }, 3)
.catch(error => {
    console.log(error.message)
})

Events

The following events are emitted:

  • connected, this event is emitted when using the serialbridge communication method and the connection to the bridge has been established.

  • disconnected,this event is emitted when using the serialbridge communication method and the connection is disconnected.

  • status-update, this event is emitted when the value of one or more properties is updated. The data is a JSON object containing all updated properties with their values.

Logging

The Winston module is used for logging. You can configure the logging by creating your own logger, e.g.:

const logger = require('winston')

logger.remove(logger.transports.Console)
logger.add(new logger.transports.Console({
  format: logger.format.combine(
    logger.format.timestamp(),
    logger.format.colorize(),
    logger.format.printf(event => {
      return `${event.timestamp} ${event.level}: ${event.message}`
    })
  ),
  level: 'silly'
}))

By specifying the level you can control the amount of logging generated.

More information on Winston can be found here: https://www.npmjs.com/package/winston

Discovery

The module installs the midea-discover command line tool in the node_modules/.bin directory. This tool tries to find any appliances on the local network with a SmartKey and displays all relevant information required for configuring this module. When the userId and password of a SmartHome account are specified on the command line, the discovery tool will also retrieve the values for the token and key required. These values are retrieved from the Midea cloud so an Internet connection is required, but these values only need to be retrieved once.

# node_modules/.bin/midea-discover [--user=<SmartHome user>, --password=<SmartHome password>]

or

# npx midea-discover [--user=<SmartHome user>, --password=<SmartHome password>]

By default the discover command uses the 255.255.255.255 broadcast address which means only appliances on the same subnet network as the computer running the discover command will be discovered. If the appliances are on another network either specify the broadcast IP address of that network, e.g. 192.168.3.255, or use the IP address of the appliance itself using the -T or --target parameter:

# npx midea-discover --target=[target IP address]

Example response:

Found 2 appliances:

Appliance 1:
- Id: 20330721052279
- Host: 192.168.5.124
- Port: 6444
- MAC Address: c4:dc:9a:4a:1d:26
- Serial No.: 000000P0000000Q1833C9B4A14360000
- Appliance Type: Air Conditioner
- Firmware Version: 3.0.8
- New Encryption Version: true
- UDP Id: fbf0c1b2c39223c07cd284590aed9003
- Authentication Key: 022BA2C782A41BFFBED33B769AA0889E6EC858D43DB74306A207EFD74C1066B5
- Authentication Token: 9C06A28C7223C0268765BADE044DA029E933CF12C6280241C18BAF992D47B3227A15DE88FEAA0829FAA33AD684311495F43DF7D2E740E52D68220C183045D557

Appliance 2:
- Id: 12691694762294
- Host: 192.168.5.121
- Port: 6444
- MAC Address: c4:7c:2b:26:59:29
- Serial No.: 000000P0000000Q1833C9B265A190000
- Appliance Type: Air Conditioner
- Firmware Version: 3.0.8
- New Encryption Version: true
- UDP Id: 8b8c0c88c8276edde9a8acd139022118
- Authentication Key: B848C224F28E4C2AAF112C1C557707FBAF76593F95EE45DC8F693AE682BCDD0F
- Authentication Token: CF24662D8309FA055460B4E67A00EDE09117455DCBDEA7A90C97CE3B9EEDC1DF0305C36B1399C2F07FFA0935336991C856A0E13705FD7D5C79AF80D70C8322C7C
0.3.2

12 days ago

0.3.3

12 days ago

0.3.1

4 months ago

0.3.0

1 year ago

0.2.3

2 years ago

0.2.2

2 years ago

0.2.1

2 years ago

0.2.0

2 years ago

0.1.19

3 years ago

0.1.18

3 years ago

0.1.17

4 years ago

0.1.16

4 years ago

0.1.15

4 years ago

0.1.14

4 years ago

0.1.13

4 years ago

0.1.12

4 years ago

0.1.11

4 years ago

0.1.10

4 years ago

0.1.9

4 years ago

0.1.8

4 years ago

0.1.7

4 years ago

0.1.6

4 years ago

0.1.2

4 years ago

0.1.3

4 years ago

0.1.5

4 years ago

0.1.1

4 years ago