Skip to content
sm-Fifteen edited this page Sep 24, 2024 · 114 revisions

The S21 protocol was reverse engineered by inspecting the flows going between indoor air conditioning units and the standard wifi controllers. This appears to be a protocol referred to as S21, as it is the S21 connector to which the device connects. This is an older protocol, but one which there is some documentation on the Internet.

Data Packets

The data is a simple 8-bit serial at 2400 baud, even parity, two stop bits.

The packet format uses ASCII a lot, and each packet starts with STX (0x02), ends with ETX (0x03) and gets an ACK (0x06) response. Very crude.

Packet format (example request)

Hex Description
02 Packets start 02 (STX)
46 Indicates some sort of request, “F”, also seeing 52 “R”, and 44 “D”
46 Request code - this is "Q", seems to always be ASCII
Additional payload - often seems to be ASCII, but not always
97 Sum of bytes after 02 to end of payload
03 Packets end 03 (ETX)

Acknowledgement

Hex Description
06 Ack

Packet format (example reply)

Hex Description
02 Packets start 02 (STX)
47 Indicates reply, “G”, one more than request, also seen 53 “S”, and 45 “E”
51 Matching request code - this is “Q”
31 44 30 30 Payload. This example is 1D00
6D Sum of bytes after 02 to end of payload
03 Packets end 03 (ETX)

Acknowledgement

Hex Description
06 Ack

Since certain bytes have special meaning, they cannot be present in data payload. These bytes include: 02(STX), 03(ETX), 06(ACK), 0A, 15(NAK). In order to prevent these values from appearing in data stream, Daikin adds some bits, which we call "shield bits" below. Most often these constitute a value of 0x30, which is ASCII for '0'. Therefore in many cases (but not all) data bytes can also be interpreted as valid ASCII.

Unknown

Lots of commands and responses are not 100% known.

Commands

Majority of command codes consist of two characters. However this rule has exceptions:

  • FUxx, FYxx - v3 protocol commands with extended 4-character codes
  • M - 1-character code, probably obsolete, but Daikin controllers still query it .

The basic polling loop (v3) seems to consist of F/G commands: 2, 1, 3, 4, 5, 8, 9, 6, 7, B, G, K, M, N, P, Q, S, T, U00, U02, X, and less frequently R/S commands: H, N, I, a, X, d, L

Additional commands seen: H, X

Most commands have no request payload, apart from F/U which is seen with strings 02 and 04.

TBD: Update for different protocol versions

Protocol versions

There appear to be different versions of the S21 protocol supported by different units. The protocol version appears to determine which commands a unit is known to respond to, and official controllers will alter their behavior based version probing. The list of supported R commands doesn't seem to vary across versions.

For version 2 and below FY00 command isn't supported and causes a NAK response. In this case protocol version is indicated by older F8 and corresponding D8 response. Note that for protocol v3 and above this command still indicates version 2, probably for backwards compatibility with some old software.

Version 3 and beyond is indicated by FY00 command. The response code is GY00, returned version may affect the meaning and/or presence of various other commands.

Additionally, F2, FK, and FU00 commands, if supported. are used to query for optional features supported by the unit.

BRP069B41 also has own protocol version; reported in /aircon/get_model_info as cpv= and cpv_minor= parameters. The controller tries to match own version against reported by the conditioner; and uses lowest common demoninator. For example, with version set to 3.10 in the simulator: pv=3.10,cpv=3,cpv_minor=01 . This means it treats the simulated A/C as conforming to version 3.01, which it knows, despite a higher number has been reported. Based on this we can understand which versions can be seen in the wild. The following version numbers have been found to be recognized by BRP069B41: v0, v1, v2, v3.00, v3.01, v3.20.

Note

Note the model number nomenclature that Daikin follows when adding a model to the list. The first 4 letters denote the device class, not the revision.

Protocol version 0

  • "F8" result: "G8 0␀␀␀"
  • "FY00" result: NAK
  • Reported BRP069 protocol version: pv=0,cpv=0
  • Known models: FTXS**L, FTXS**G
  • Supported R commands: RA, RB, RC, RD, RE, RF, RG, RH, RI, RK, RL, RM, RN, RW, RX, Ra, Rb, Rd, Re, Rg, Rz
  • Supported F commands: F1, F2, F3, F4, F5, F8
  • Supported miscellaneous commands: A, M, V

Protocol version 3.20

  • "F8" result: "G8 0200"
  • "FY00" result: "GY00 0230"
  • Reported BRP069 protocol version: pv=3.20,cpv=3,cpv_minor=20
  • Known models: FTXF**D, FVXM**?, FVXM**A

Protocol version 3.40

  • "F8" result: "G8 0200"
  • "FY00" result: ???
  • Reported BRP069 protocol version: pv=3.40,cpv=3,cpv_minor=20
  • Known models: FTXM**R

BRP069B41 controller does not recognize this version and considers it to be 3.20. It looks like newer versions are only supported in new cloud-only controllers.

Commands support matrix for different protocols.

"BRP069B41" column indicates whether a command is used by that controller. "Optional" means that the command is not mandatory, and the A/C is allowed to respond NAK. "Rudimentary" means that the command is supported, but the response looks like a stub and most likely not used.

Command Response Payload length Semantics v1 v2 v3 BRP069B41 Notes
A C 1 (i.e. x) Ping ? ? Yes Yes No Replies back with the same payload. On payloads longer than 1 byte replies something.
M M 4 Supposedly model code for protocol v1 Yes Rudimentary Rudimentary <=v2 Reports 'FFFF' (ASCII) for v2+ conditioners. BRP069B41 queries but appears to ignore it.
V V 4 Yes Yes No 4 digit hex, seems constant per unit
VS000M VS 14 Indoor unit firmware version Yes Yes >=v3.01 Only polled once
D3 N/A 3 Set on/off timer Yes Yes No
DJ N/A 4 Unknown Yes Yes Yes
DL N/A 4 Unknown Yes Yes Payload: '0000' ASCII
DY10 N/A 8 Unknown Yes >=v3.00 Payload: 41 38 44 33 36 36 36 46
DY20 N/A 4 Unknown Yes >=v3.00 Payload:
F1 G1 4 Power, mode, setpoint, fan speed setting Yes Yes Yes Yes
F2 G2 4 Optional features Yes Yes Yes Yes
F3 G3 4 On/off timer. "Powerful" mode on some models (?) Yes Yes Yes Yes
F4 G4 4 Error status(?) Yes Yes Yes Yes
F5 G5 4 Swing, humidity setting Yes Yes Yes Yes Supported values depend on optional features, see F2
F6 G6 4 Powerful, Comfort, Quiet, Streamer, Sensor modes' LED control Partial Yes Yes See description for protocol version details.
F7 G7 4 Demand mode, econo mode No Yes Yes Yes
F8 G8 4 Protocol version (up to v2) Yes Yes Rudimentary Yes
F9 G9 4 Coarse indoor, outdoor temperature (℃), humidity (%) No Yes Yes Yes Format: bytes 0, 1 are 0x80 + value/2. Byte 2 is '0' + value. Meaning: Byte 0: indoor temperature in C (granularity of 1C, rounded down), byte 1: outdoor temperature in C (granularity of 1C, rounded down), byte 2: indoor humidity in units of 1% (granularity of 5%, rounded down). e.g. 0xac:aa:4e:30 22C inside, 21C outside, 30% humidity
FA GA 4 No Yes
FB GB 4 No Yes Yes Yes
FC GC 4 Model code No Yes Yes Yes Only polled once. First byte appears to indicate unit size/capacity
FG GG 4 IR remote counter No Yes Yes Yes increments on each IR command
FK GK 4 Optional features (v2+) No Yes Yes Yes
FL GL 4 No Yes
FM GM 4 Power consumption No Yes Yes Yes 4 digit ASCII encoded hex number in reverse- indicates total Wh/10
FN GN 4 No Yes Yes Yes
FP GP 4 No Yes Yes Yes
FQ GQ 4 No Yes Yes Yes
FR GR 4 Louver position setting No Yes Yes Yes
FS GS 4 No Yes Yes Yes
FT GT 4 Unknown No Yes Yes Yes potentially outdoor unit capacity in units
FU00 GU00 32 Optional v3+ features No No >=v3.20 >= v3.20 Only polled once.
FU02 GU02 32 Allowed temperature ranges No No Yes >= v3.01
FU04 GU04 32 Unknown No No >=v3.20 >= v3.20
FV GV Unknown No ? No ? >= v3.01 ? No Found by brute-forcing; tested on FTXF20D5V1B (v3.20), S22ZTES-W (v3.00) and ATX20K2V1B (v2)
FX00 GX00 Unknown No No Yes Yes
FX10 GX10 Unknown No No Yes Yes
FX20 GX20 Unknown No No Yes Yes
FX30 GX30 Unknown No No Yes Yes
FX40 GX40 Unknown No No Yes Yes
FX50 GX50 Unknown No No Yes Yes
FX60 GX60 Unknown No No Yes Yes
FX70 GX70 Unknown No No Yes Yes
FX80 GX80 Unknown No No Yes Yes
FX90 GX90 Unknown No No Yes Yes
FXA0 GXA0 Unknown No No Yes Yes
FXB0 GXB0 Unknown No No Yes Yes
FXC0 GXC0 Unknown No No Yes Yes
FY00 GY00 4 Protocol version (v3+) No No Yes Yes Only polled once
FY10 GY10 8 Unknown No No Yes Yes Only polled once
FY20 GY20 4 Unknown No No Yes Yes Only polled once
RA SA 1 Power on/off Yes Yes Yes No
RB SB 1 Current indoor unit mode? Yes Yes Yes No One ASCII digit, using the same mapping as F1. Seems to always reflect the setting from F1, even if the mode is changed while the unit is off.
RC SC 4 Temperature set point Yes Yes Yes No 4 digit ASCII encoded signed decimal in reverse e.g. "542+" for 24.5C
RD SD 3 On timer setting Yes Yes Yes No
RE SE 3 Off timer setting Yes Yes Yes No
RF
RG SG 1 Fan mode Yes Yes Yes No "A" = auto (or night on some models), "B" = night mode (on other models), "1" through "7" for fixed speeds
RH SH 4 Indoor temperature Yes Yes Yes Yes
RI SI 4 Liquid temperature Yes Yes Yes Yes
RK SK 3 Fan set point Yes Yes Yes No
RL SL Fan speed Yes Yes Yes Yes
RM SM 4 Louvre angle set point Yes Yes Yes No
RN SN 4 Vertical swing angle Yes Yes Yes Yes
RW SW 2 Yes Yes Yes No
RX SX Target temperature (not set point, see details) Yes Yes Yes Yes
Ra Sa 4 Outside temperature (0.5C granularity) Yes Yes Yes Yes
Rb Sb 3 Indoor frequency command signal Yes Yes Yes No
Rd Sd 3 Compressor frequency Yes Yes Yes Yes
Re Se 3 Indoor humidity (1% granularity) Yes Yes Yes No
Rg Sg 1 Compressor on/off Yes Yes Yes No
Rz Sz 4 System state/System query? Yes Yes ? No Empty reply on my FTXF20 (v3), but was turned off

Commands with data

The F/U command has string 02 or 04. The F/X command seems to regularly have a string progressing 00, 10, … C0, and repeating. Each provides a different response string. The D commands appear to be to change settings, and also appear not to get a response, i.e. no E message. However, whilst testing the app is reporting errors.

D1 command

The D1 command sets the power, mode, temp, and fan rates. It has a 4 character payload.

Pos Description Values
1 Power 0: 0ff
1: On
2 Mode 0: ?
1: Auto
2: Dry
3: Cool
4: Heat
6: Fan
7: Auto (reported in status)?
3 Temp @: 18.0C
A: 18.5C

W: 29.5C
X: 30.0C
0x80: N/A (for dry mode)
4 Fan 3: Low

7: High
A: Auto
B: Quiet or Q for Night?

D2 command

The D2 command is unknown. It has a 1 character payload.

Pos Description Values
1 Unknown 0

D3 command

Set on/off timer
Payload size: 3 bytes

Sets on/off timer value. Payload is exactly the same as first 3 bytes, reported by F3:

  • byte 0:
    • Bit 0 - On timer is set
    • Bit 1 - Off timer is set
    • Bits 4, 5 - shield bits, making up 0x30 (ASCII '0')
  • byte 1 - On timer setting
  • byte 2 - Off timer setting

Timer settings range from 1 to 12 hours, and corresponding values are: 0x36, 0x3C, 0x42, 0x48, 0x4E, 0x54, 0x5A, 0x60, 0x66, 0x6C, 0x72, 0x78. In other words, time value starts from 0x30 (which would be 0), then one hour equals to an increment of 6. This gives an idea that perhaps timer granularity is 10 minutes (1/6 of hour), but it's unclear if the unit would accept them properly.

D5 command

The D5 command controls the louver swing. It has a 4 character payload.

Pos Description Values
1 Swing 0: Off
1: Vertical swing
2: Horizontal swing
7: Both swing
1 Swing? 0: Off
?: On
1 Unknown 0
1 Unknown 0

D6 command

The D6 command controls the “powerful” setting. It has a 4 character payload.

Pos Description Values
1 Powerful 0: Off
2: On
p: Comfort
2 Unknown 0
3 Unknown 0
4 Unknown 0? 4?

This command is optional for v2 conditioners. ATX20K2V1B does not support it, returning NAK.

D7 command

The D7 command controls the “econo” settings. It has a 4 character payload.

Pos Description Values
1 Unknown 0
2 Econo 0: Off
2: On
3 Unknown 0
4 Unknown 0

DH command

The DH command is unknown.

Pos Description Values
1 Unknown 1
2 Unknown 1
3 Unknown 0
4 Unknown 0

DJ command

Purpose unknown
Payload length: 4 bytes

This command is send by BRP069B41 controller on startup. The payload is sometimes '2010' and sometimes '2030' ASCII. The effect is the following:

  1. Byte 2 bit 7 in F2 is set to 1
  2. Byte 3 in F3 is changed from 0x00 to 0x30

Query commands

The following commands have no payload, when sent to the conditioner. They are used to query various values, and produce a response, whose body contains values requested

F2 command

Query optional features
Response format: G2 [byte0] [byte1] [byte2] [byte3]
Payload bytes are bit masks:

  • byte0
    • bit 0 - Unkown. set to 1 on CTXMxxRVMA, ignored by BRP069B41
    • bit 1 - Zero
    • bit 2 - Swing (any kind) is avaiiable
    • bit 3 - Horizontal swing is available
    • bit 4 - Shield bit (0x30)
    • bit 5 - Shield bit (0x30)
    • bit 6 - Zero
    • bit 7 - Zero
  • byte1
    • bit 0 - Unkown. set to 1 on CTXMxxRVMA, ignored by BRP069B41
    • bit 1 - Awlays 1, unknown
    • bit 2 - Zero
    • bit 3 - Unknown. Reflected by BRP069B41 in aircon/model_info. 0 => type=C, 1 => type=N
    • bit 4 - Shield bit (0x30)
    • bit 5 - Shield bit (0x30)
    • bit 6 - Zero
    • bit 7 - Zero
  • byte2 - seen to be 0x00 on startup
    • bit 7 - Set to 1 by DJ command. Purpose is unknown.
  • byte3
    • bit 0 - Zero
    • bit 1 - "humidity" operation mode is available
    • bit 2 - Zero
    • bit 3 - Zero
    • bit 4 - Humidity setting is available for additional operation modes (see matrix below)
    • bit 5 - Zero
    • bit 6 - Zero
    • bit 7 - Always 1. Perhaps shield ?

Humidity settings availability matrix (reverse engineered from Daikin online controller app)
s_humd is a per-mode bitmask, presented by BRP069B41 in /aircon/model_info

bit 4 = 0, bit 1 = 0; s_humd=0
Humidity settings not available

bit 4 = 1, bit 1 = 0; s_humd=146 (0x92)

Mode\Setting Off Low STANDARD High Continuous
Auto - - - - -
Cool y y y y y
Heat - - - - -
Fan - - - - -
Dry y - y y y

bit 4 = 0, bit 1 = 1; s_humd=165 (0xA5)

Mode\Setting Off Low STANDARD High Continuous
Auto y y y y y
Cool - - - - -
Heat y y y y y
Fan - - - - -
Dry - - - - -
Humidify y - y y y

bit 4 = 1, bit 1 = 1; s_humd=183 (0xB7)

Mode\Setting Off Low STANDARD High Continuous
Auto y y y y y
Cool y y y y y
Heat y y y y y
Fan - - - - -
Dry y - y y y
Humidify y - y y y

F3 command

On-off timer
Response format: G3, payload size: 4 bytes

  • byte 0:
    • Bit 0 - On timer is set
    • Bit 1 - Off timer is set
    • Bits 4, 5 - shield bits, making up 0x30 (ASCII '0')
  • byte 1 - On timer setting
  • byte 2 - Off timer setting
  • byte 3 - Reports 0x00 after bootup, changed to 0x30 by DJ. Meaning unknown.

Timer settings range from 1 to 12 hours, and corresponding values are: 0x36, 0x3C, 0x42, 0x48, 0x4E, 0x54, 0x5A, 0x60, 0x66, 0x6C, 0x72, 0x78. In other words, time value starts from 0x30 (which would be 0), then one hour equals to an increment of 6. This gives an idea that perhaps timer granularity is 10 minutes (1/6 of hour), but it's unclear if the unit would accept them properly.

On majority of units if the timer is disabled, the respective setting bytes are set to 0xFE. However, on ATX20K2V1B and S22ZTES-W they read as 0x30 in this case. Experiments with BRP069B41 controller on simulator show that it doesn't accept response of 0x30 0x30 0x30 0x00; it sends NAK and keeps retrying, falling into "SERIAL IF FALURE" state. It's also known that this controller actually works with ATX20K2V1B. I tried snooping boot process on my ATX20K2V1B; that yielded no clue. The response on bootup is 0x30 0x30 0x30 0x00; and everything works just fine.

According to commit 0c5f769894365d344012b36846f0b91023840d94 on some models bit 1 of byte 3 is used as "Powerful" mode flag. Those models apparently do not support F6 command, but unfortunately there's no information on which exact model that is. Given the above, that could be a mistake.

F4 command

Response code: G4, payload length: 4 bytes

  • byte0: 0x30 ('0')
  • byte1: 0x00
  • byte2
    • Bit 5: Conditioner internal error flag. If reported as 1, BRP069B41 only polls 4 commands F1-F3-F4-F2 and reports in /aircon/model_info:
      ret=SERIAL IF FAILURE,err=252
      Experiments show, that once read, the bit resets to 0. It's not known which actions cause it to raise.
  • byte3: 0x30 ('0')

F6 command

Special modes status
Response code: G6, payload length: 4 bytes

  • byte 0: Special modes.
    • bit 2 - "Powerful" mode on
    • bit 6 - "Comfort" mode on
    • Bit 7 - "Quiet" mode on
  • byte 1
    • bit 7 - streamer mode on
  • byte 2 - not used ?
  • byte 3 - according to current Faikin code:
    • Bit 3: "Sensor" mode on
    • Bits 3, 4 (mask 0x0C): if both set (value & 0x0C == 0x0C), LED is turned off.

Protocol version specifics:
Set of available special modes is determined by FU00, which is only supported in protocol v3. Early protocol versions (tested on ATX20K2V1B, also reported for FTXS series, which is known to be v0) support this command too, but only report "Powerful" mode. Those conditioners also appear not to support respective D6 control command. Therefore Faikin currently has no way of controlling special modes on those models. It's unknown whether they can be controlled over S21 protocol in principle.

Commit 0c5f769894365d344012b36846f0b91023840d94 suggests that some models don't support this command at all. If such a case "Powerful" mode flag would come from F3. Unfortunately information on which A/C model exhibits this behavior has been lost.

F8 command

Protocol version (old, prior to v3) Response code: G8, payload length: 4 bytes

  • byte0: Only observed 0x30 (ASCII '0') so far
  • byte1: Version number, one ASCII digit. Reported in /aircon/get_model_info as pv= . v0 conditioners may just report 0x00 here (seen in FTXS50G), but experiments on BRP0690B41 show that there's no difference; the controller most likely masks shield bits out using "value & ~0x30".
  • byte2, byte3: Only seen 0x00 (in ATX20K2V1B, real v2 protocol), or ASCII '0' (in v3 conditioners). Also seems to be ignored by Daikin controller.

This command only reports real version number prior to v3. v3 protocol froze F8 response to '0200' ASCII (which stands for v2) and superseded this command by FY00. Daikin controller distinguishes between protocol versions by probing for FY00 command, which is not recognized and returns NAK prior to v3.

Below is a table of known responses for F8:

D8 Response (hex) protocol version Example
0x30 0x32 0x00 0x00 2 1, 2
0x30 0x32 0x30 0x30 2 1
0x30 0x00 0x00 0x00 0 1, 2

FC command

Model code
Response code: GC, payload length: 4 bytes

Payload is 4 ASCII characters in reverse order (byte3 to byte0), which are reported as model= in /aircon/get_model_info. The controller by itself does not seem to do anything with this string, just pass.

The model code always looks like a hexadecimal number, nothing like customer-visible model code, printed on the label. This is most likely Daikin's internal model number, which can be looked up in some proprietary database.

FK command

Query extra optional features [protocol v2]
Response code: GK, payload length: 4 bytes

  • byte0
    • bit 0 - Unknown. Reported as acled= value by BRP069B41 in /aircon/get_model_info
    • bit 1 - Zero
    • bit 2 -
    • bit 3 - "Laundry" operation mode is available.
    • bit 4 - Shield bit (0x30)
    • bit 5 - Shield bit (0x30)
    • bit 6 -
    • bit 7 -
  • byte1
    • bit 0 - Unknown. Reported as elec= value by BRP069B41 in /aircon/get_model_info
    • bit 1 - Zero
    • bit 2 - Reported as temp_rng= value by BRP069B41 in /aircon/get_model_info. Used by Japanese controllers to select between the two temperature ranges.
    • bit 3 - Reported as m_dtct= value by BRP069B41 in /aircon/get_model_info. Probably "motion detector" AKA "Intelligent eye" availability
    • bit 4 - Shield bit (0x30)
    • bit 5 - Shield bit (0x30)
    • bit 6 - Unknown. Reported 1 by FTXF20D5V1B
    • bit 7 - Zero
  • byte2
    • bit 0 - Unknown. Reported as "ac_dst=" value by BRP069B41 in /aircon/get_model_info: 0 => ac_dst=jp; 1 => ac_dst=--
    • bit 1 - Indicates simple "Humidify" mode implementation. When set to 1, humidity setting is not available regardless of respective F2 bits; and BRP069B41 reports s_humd=16 in /aircon/get_model_info
    • bit 2 - Fan controls available. When set to 0, swing bits in F2 response are ignored; and neither fan speed nor swing controls are available in "Daikin online controller" app.
    • bit 3 - Unknown. Reported as "disp_dry=" value by BRP069B41 in /aircon/get_model_info
    • bit 4 - Shield bit (0x30)
    • bit 5 - Shield bit (0x30)
    • bit 6 - Zero
    • bit 7 - Zero
  • byte3
    • bit 0 - Demand mode if available. Daikin controller ignores this bit in protocol <= 2

FR command

Louver angle setting
Response code: GR, payload length: 4 bytes

  • byte 0 - ASCII character; reflects the requested louver angle setting:
    • '?' - Swing is active, no constant setting
    • '0' - Default position. Also reported on units, which don't support manual angle setting.
    • '1' - '5' - Manual setting in order: Upper position, high middle position, middle position, low middle position, lower position
  • bytes 1 - 3 - always '0' ASCII, reserved.

FU00 command

Special modes availability flags Response code: GU00, payload length: 32 bytes

  • byte 0 - "Powerful" mode availability flag. 0x33 - enabled, 0x30 - disabled
  • byte 1 - "Econo" mode availability flag. 0x33 - enabled, 0x30 - disabled
  • byte 3 - unknown. Set to 0x33 (enabled) on FTXF20D5V1B, but no mode_info flag was found.
  • byte 3 - unknown
  • byte 4 - unknown. Set to 0x33 (enabled) on FTXF20D5V1B, but no mode_info flag was found.
  • byte 5 - "Streamer" mode availability flag. 0x33 - enabled, 0x30 - disabled
  • the rest - unknown, could be reserved.

Bytes 0, 1 and 5 effectively make up a bitmask, which is reported by Daikin controller as en_spmode= value in /aircon/get_model_info.

Apparently 0x30 and 0x33 are the only legitimate byte values for this command. Experiments show that 0x31 and 0x32 are treated no differently from 0x30; and value of 0x34 causes the controller to report "SERIAL IF FAILURE" error with code 252. I didn't try any other values because it's very time-consuming process. Since the command is only polled once; after every change the controller has to be rebooted.

Example payload from FTXF20D5V1B: 0x33 0x33 0x33 0x30 0x33 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30

FU02 command

Temperature limits
Response code: GU00, payload length: 32 bytes

  • byte 0 - unknown
  • byte 1 - Unknown, also looks like temperature limit. Reported by Daikin controller as atlmt_l= in /aircon/get_model_info if enabled by byte 0 bit 6 of FK command. Valid values are from 0xA0 to 0xB0 (inclusive); the value is determined as: atlmt_l = (byte - 0xA0) / 2.0. This yields range from 0 to 8.0. If byte value is outside of the valid range, the atlmt_l parameter value defaults to zero.
  • byte 2 - Minimum allowed temperature for Heat mode. Reported by Daikin controller as hmlmt_l= in /aircon/get_model_info. Valid values are from 0x30 to 0x6F (inclusive); the value is determined as: hmlmt_l = (byte - 0x30) / 2.0 + 10.0. This yields range from 10.0 to 41.5 . If byte value is outside of the valid range, the hmlmt_l parameter is not present.
  • byte 3 - unknown
  • byte 4 - unknown
  • the rest - looks like unused. 0xFF is often default content of unwritten EEPROMs.

Example payload from FTXF20D5V1B: 0xA0, 0xA0, 0x30 ,0x31, 0x30, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF.

FU04 command

Unknown
Response code: GU04, payload length: 32 bytes
Seems to contain very long hexadecimal value, which slowly increases over time. The A/C has been turned off. Example payloads from FTXF20D5V1B:
0x36, 0x43, 0x37, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF - non-FF bytes read as 00000000000007C6 (assuming inversion)
0x30, 0x44, 0x37, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF - 00000000000007D0

FY00 command

Protocol version (v3 and beyond)
Response code: GY00, payload length: 4 bytes

  • bytes 0,1: Protocol version minor as inverted ASCII
  • bytes 2,3: Protocol version major as inverted ASCII Example: response '0230' stands for protocol version 3.20
    For protocols version below 3 this command isn't supported and returns NAK; in this case old F8 is used

FY10 command

Unknown
Response code: GY00, payload length: 8 bytes The returned value is an 8-byte hexadecimal string of unknown purpose. Could be conditioner firmware's git hash.
BRP069B41 controller only queries this command once in lifetime. Therefore it clearly has to do with A/C identification. Example payload from FTXF20D5V1B: {'A', '8', 'D', '3', '6', '6', '6', 'F'}

FY20 command

Unknown
Response code: GY20, payload length: 4 bytes The returned value is an 4-byte hexadecimal string of unknown purpose.
BRP069B41 controller only queries this command once in lifetime. Therefore it clearly has to do with A/C identification. Example payload from FTXF20D5V1B: {'E', '4', '0', '2'}

M command

Response code: M, payload size: 4 bytes. 5 bytes total.
One of rare, perhaps very old, commands, whose code only consists of one byte.Unknown for sure, but looks like model code for protocol v0. According to https://github.com/revk/ESP32-Faikin/issues/408#issuecomment-2313256060
The command is supported in v2+ protocols, but the only seen reply is 'MFFFF' (ASCII). The controller doesn't seem to do anything about the payload.

VS000M command

Indoor unit firmware version
Response code: VS, payload size: 14 bytes

  • Bytes 0 - 7 - firmware version in text format in reversed ASCII as usual. Shown as "Indoor unit software" on "Indoor unit" page by Onecta app when using new cloud-only controller. Info provided by @nikbyte using FTXA35C2V1B's integrated controller.
  • Bytes 8 - 13 - Always read as '00000M' again in reversed ASCII.

Example payload: 0x31 0x30 0x31 0x37 0x31 0x30 0x32 0x32 0x4D 0x30 0x30 0x30 0x30 0x30 ; firmware version "22017101"
This command is only polled once. BRP069B41 controller also polls this command, but no HTTP API endpoints are known to expose this information.

RH command

Home temperature
Response code: SH, payload length: 4 bytes
Payload format: signed ASCII in reverse order with one decimal place implied. Example: '123+' would stand for +32.1 C

RI command

Inlet temperature Response code: SI, payload length: 4 bytes
Payload format: signed ASCII in reverse order with one decimal place implied. Example: '123+' would stand for +32.1 C

RL command

Fan speed (RPM)

RN command

Louver angle
Response code: SN, payload length: 4 bytes
Payload formart: signed ASCII in reverse, the same as temperature. On my ATXF20 with swing on i observed the value changing from +000 to +090 and back.

RX command

Target temperature
Response code: SX, payload length: 4 bytes
Payload format: signed ASCII in reverse order with one decimal place implied. Example: '123+' would stand for +32.1 C
Temp. the indoor unit is actually trying to match, accounts for any powerful mode or intelligent eye modifiers or similar (heuristics are detailled in service manuals)

Ra command

Outside temperature Response code: Sa, payload length: 4 bytes
Payload format: signed ASCII in reverse order with one decimal place implied. Example: '123+' would stand for +32.1 C

Rb command

Unsigned ASCII decimal. Represents how much this indoor unit currently "pulls" on the compressor. Ranges from 0-15 indicating no load through to maximum load, with a value determined by the difference between the target and indoor temperatures. The compressor uses this signal to determine its target operating frequency (documented in service manuals).

Rd command

Compressor speed (RPM)

Re command

Indoor humidity
Response code: Se, payload length: 3 bytes
Payload format:3 digit unsigned ASCII decimal in reverse, e.g. 970 means 79% humidity. Units with no humidity sensor seem to always report 50%.

Rz command

Seems to reflect the state of the full system, including the outdoors unit and what other indoor units are doing. Format initially differs between units in a multizone configuration. Sending a third byte, like Rz1 or Rz2 seems to change the return format in a "sticky" way (Rz subsequently returns what Rz* last returned), which the remote control seems to reset. The initial format variance between indoor units likely reflects the last probed field of some internal state querying routine.

F/G Responses

TODO: Rewrite this section and merge with the previous

The F/G responses are various lengths. Mostly text, but not always.

Opcode Description
G1 Same as sent with D1
G3 This seems to be related to start/stop controls, and so presumably can be set with D3
G5 Same as sent with D5 but last byte is 0x80
G6 Same as sent with D6
G7 First two characters same as sent with D7, but the AG on the end.
G9 First two bytes appear to be temp (inside, outside) as 0x80+C*2

G3 appears to be:-

  • 0/1/2/3 for none, start, stop, start+stop
  • Start time byte
  • Stop time byte
  • 0x80

The times appear to be 0xFE when not set, and these example values when set…

  • 23:00=b=98
  • 23:30=f=102
  • 06:00=8d=141=-115, or 0x80+13
  • 07:00=92=146=-110, or 0x80+18

More tests needed to work out the exact pattern.

Clone this wiki locally