crankyoldgit / IRremoteESP8266

Infrared remote library for ESP8266/ESP32: send and receive infrared signals with multiple protocols. Based on: https://github.com/shirriff/Arduino-IRremote/
GNU Lesser General Public License v2.1
2.94k stars 831 forks source link

Support for Maxwell AC (Probably advanced Mirage support) #1573

Closed akram closed 2 years ago

akram commented 3 years ago

Version/revision of the library used

IRremoteESP8266 2.7.18 which comes with Tasmota 9.5.0

Describe the bug

I have a Maxwell AC (not a very well known brand) that seems to be using Mirage protocol, however controlling it does not work. After receiving and replaying payload data, the IRSend command does not trigger any action on the AC side.

To Reproduce

Install tasmota 9.5 (uses IRremoteESP8266 uses v2.7.18 ) capture data from the remote controller and replay it. No reaction on the AC side e.g.

15:48:47.093 MQT: tasmota_38B3E6/tele/RESULT = {"IrReceived":{"Protocol":"MIRAGE","Bits":120,"Data":"0x566C000020D800000C320B00320F64","Repeat":0}}
15:48:48.596 MQT: tasmota_38B3E6/tele/RESULT = {"IrReceived":{"Protocol":"MIRAGE","Bits":120,"Data":"0x566C0000201A00000C320B02320F5C","Repeat":0}}
15:48:56.001 MQT: tasmota_38B3E6/tele/RESULT = {"IrReceived":{"Protocol":"MIRAGE","Bits":120,"Data":"0x566C000020D800000C320B09320F6D","Repeat":0}}
15:48:57.746 MQT: tasmota_38B3E6/tele/RESULT = {"IrReceived":{"Protocol":"MIRAGE","Bits":120,"Data":"0x566C0000201A00000C320B0B320F65","Repeat":0}}
15:49:01.191 MQT: tasmota_38B3E6/tele/RESULT = {"IrReceived":{"Protocol":"MIRAGE","Bits":120,"Data":"0x566C000020D800000C320B0E320F72","Repeat":0}}
15:49:19.560 MQT: tasmota_38B3E6/tele/RESULT = {"IrReceived":{"Protocol":"MIRAGE","Bits":120,"Data":"0x566C0000201A00000C320B20320F5C","Repeat":0}}

Example code used

Using tasmota, enable raw mode with:

SetOption58 1
18:53:50.697 MQT: tasmota_38B3E6/tele/RESULT = {"IrReceived":{"Protocol":"MIRAGE","Bits":120,"Data":"0x56700000201A00000C320B1D371256","Repeat":0,"RawData":"+8455-4135+590-570D-1590CeC-550CeCfCeCfCfCfCfCfCeC-1610DeCfCfCfCfCfCfCfC-575DfCfCfCdDfCdDhDfCfCfCfCfCfC-555CeCdDfCdDeCfCgDgDfCfCdDfCfCfCfCfCfCfCfCfCfCfCdDfCfCfCfCfCdDeCeCfCfCfCfCfCeCfCfCeCeCdDfCeCgDfCeCfChDfCdDeCfCeCeCeCfCfCfCgDeCeCfCeCeCfCdDhDeCfCfCgDfCfCfCdDeCeCdDgDf+595gDfC","RawDataInfo":[243,243,0]}}

and replay the received raw data after converting it

18:59:17.896 CMD: IRSend raw 8450,4130,590,575,570,1590,590,1610,570,550,590,1590,590,550,590,1590,590,550,590,1610,570,1590,590,1610,570,1590,590,550,590,1610,570,1590,590,550,590,570,570,550,590,550,590,570,570,550,590,550,590,570,570,570,570,570,570,550,590,550,590,550,590,550,590,570,570,550,590,550,590,570,570,550,590,550,590,570,570,550,590,1590,590,555,590,570,570,570,570,1610,570,550,590,1610,570,1590,590,550,590,570,570,550,590,550,590,570,570,570,570,550,590,550,590,550,590,570,570,570,570,570,570,570,570,575,570,575,570,570,570,555,590,570,570,570,570,550,590,570,570,1615,570,1610,570,550,590,570,570,570,570,570,570,550,590,1610,570,550,590,575,570,1590,590,1610,570,550,590,570,570,1590,590,1610,570,550,590,1590,590,575,565,555,590,550,590,550,590,575,570,570,570,1590,590,570,570,570,570,1590,590,550,590,570,575,1590,590,570,570,1590,590,550,590,1610,570,1610,570,570,570,550,590,570,570,1610,570,555,590,575,565,1590,590,550,590,550,590,550,590,550,590,1610,570,550,590,1610,570,1610,570,575,570,1610,570,570,570
18:59:18.001 MQT: tasmota_38B3E6/stat/RESULT = {"IRSend":"Done"}

Expected behaviour

The AC reacts to the command:

Output of raw data from [IRrecvDumpV2.ino]

I don't have the required hardware to run this thest.

Note: Output from Tasmota is not acceptable. We can't easily use their raw format. arf....I just read this after submitting the bug.

What brand/model IR demodulator are you using?

YFJ IR Bridge (Tuya)

Circuit diagram and hardware used (if applicable)

None

I have followed the steps in the [Troubleshooting Guide]

Yes

Has this library/code previously worked as expected for you?

No

Other useful information

Before upgrading to 2.7.18 , I was using a Tasmota version embedding IRremote that does not support Mirage. At that time, Tasmota was IRReceiving an UNKNOWN protocol with a payload of 122bits. After upgrading, it is now seen as MIRAGE with 120bits payload. During my AC remote captures, I was also seeing sometings for IRreceived with KELON protocol. So, I wonder if the AC is really using MIRAGE and if its protocol is interpreted as is, but that could be a different protocol.

Also, one important thing: same commands and even same state does not have the same data. Some part of the payload is identical accross calls, but, some others always vary whatever the sent state.

crankyoldgit commented 3 years ago

Also, one important thing: same commands and even same state does not have the same data. Some part of the payload is identical accross calls, but, some others always vary whatever the sent state.

Can you please elaborate on this with examples/documentation/data etc?

After receiving and replaying payload data, the IRSend command does not trigger any action on the AC side.

Where is the IRSend command you're using? I can't seem to see it in your report. (Not that I know how that bit of Tasmota works, but I can make a good guess)

8450,4130,590,575,570,1590,590,1610,570,550,590,1590,590,550,590,1590,590,550,590,1610,570,1590,590,1610,570,1590,590,550,590,1610,570,1590,590,550,590,570,570,550,590,550,590,570,570,550,590,550,590,570,570,570,570,570,570,550,590,550,590,550,590,550,590,570,570,550,590,550,590,570,570,550,590,550,590,570,570,550,590,1590,590,555,590,570,570,570,570,1610,570,550,590,1610,570,1590,590,550,590,570,570,550,590,550,590,570,570,570,570,550,590,550,590,550,590,570,570,570,570,570,570,570,570,575,570,575,570,570,570,555,590,570,570,570,570,550,590,570,570,1615,570,1610,570,550,590,570,570,570,570,570,570,550,590,1610,570,550,590,575,570,1590,590,1610,570,550,590,570,570,1590,590,1610,570,550,590,1590,590,575,565,555,590,550,590,550,590,575,570,570,570,1590,590,570,570,570,570,1590,590,550,590,570,575,1590,590,570,570,1590,590,550,590,1610,570,1610,570,570,570,550,590,570,570,1610,570,555,590,575,565,1590,590,550,590,550,590,550,590,550,590,1610,570,550,590,1610,570,1610,570,575,570,1610,570,570,570

I can confirm that the library does decode the above as a MIRAGE protocol with a code of 0x566F0000201A00000C320B2435125A

Note: The library only has basic support for this (MIRAGE) protocol. That means it can send & receive state codes. Sort of like the number above. It does NOT have detailed support for this protocol yet. i.e. You can't set temperature & modes etc. If you want that support, you need to do the protocol analysis. e.g. Follow the instructions here: https://github.com/crankyoldgit/IRremoteESP8266/wiki/Adding-support-for-a-new-AC-protocol

You can also read through #1289 & #1291

akram commented 3 years ago

Can you please elaborate on this with examples/documentation/data etc?

Here the example: My AC is turned ON, temperatutre is 16°C (its minimum value) I press the temperature Up button (temperature is now 17°C) I press the temperature Up button (temperature is now 18°C) I press the temperature Down button (temperature is now 17°C) I press the temperature Down button (temperature is now 16°C) I press the temperature Down button (temperature is now 16°C) I press the temperature Down button (temperature is now 16°C)

Here are the captured data:

16:55:17.725 MQT: tasmota_38B3E6/tele/RESULT = {"IrReceived":{"Protocol":"MIRAGE","Bits":120,"Data":"0x566D0000201A00008C320B163A1064","Repeat":0,"RawData":"+8460-4135+590-555C-1590Ce+620-525C-1595C-550CeCdCeCi+615-1570CeCiCeJ-1565CiCiCiCdCdCdCiCiCdCdCiCdCdCdCdCiCiCiCdCdCiCdCeCdCdCdCeCd+640-1545Ce+585dCdCiCiCiCdCiCiCdJ-530+595iCiCiCdCiCiCiCiCdCiCdCeChCdCdCdCeCdCeCdOdCeChCiCdCeCeJpCeCdCiCdCdCdCeCeJpCeOdCiC-575+565iJlCiCeJkChFgCdOdCdCdCiCeCdCdCdCiCiChJgCdJlCeJpJ","RawDataInfo":[243,243,0]}}
16:55:22.466 MQT: tasmota_38B3E6/tele/RESULT = {"IrReceived":{"Protocol":"MIRAGE","Bits":120,"Data":"0x566E0000201A00008C320B1C3A106B","Repeat":0,"RawData":"+8475-4110+585-560C-1590C-1595C-555+590eHgCeHgHgCf+615-1570CfCg+610jC-1600D-580H-550HgInDgCgCdCdDmCdCdCgCdK-530CgCgCgHgCgCgCgCdCfHgCgHgCfCgHfIjHgCgCgCgHgCgHnDmDcKoCgHmDm+565gCgCgHgHgHnHnHgCfCfIoCgCdI-1565HgHeHgCgCfIqHdCgCfCfHgCfCdCgCgCgHgKoCfCfCfKoKoCmPnMlCgCfCfHeKoCgHgCdHgCgCeHgCdCdCfCfHmHqHdCeHfCgH","RawDataInfo":[243,243,0]}}
16:55:25.964 MQT: tasmota_38B3E6/tele/RESULT = {"IrReceived":{"Protocol":"MIRAGE","Bits":120,"Data":"0x566D0000201A00008C320B203A105F","Repeat":0,"RawData":"+8455-4115+635-535+585-1595Ef+590-555E-1600Eh+560-1620EjEfEhEiG-1590EhEfEiGhEhEhEjG-550GmG-580JhGnJhEjEhGhGhEhGmEhGhEhGhEmGhEfEhGhEh+615-1565EhEfEfGhJnEjEhO-530EjEhGh+610qJnRqEjGhNe+565nJhOmJhRqEhEjGlGlGhEhEhGlGhGfEhEjEfEfJnGhJkEiEjEfGhGhEhEh+605dEhGhJnGhEfEhGhEhJkGhGlR-1570GfGhEjGhEhEhGmEfGhGhOqGfEfEiElEfGjEfEhE","RawDataInfo":[243,243,0]}}
16:55:28.718 MQT: tasmota_38B3E6/tele/RESULT = {"IrReceived":{"Protocol":"MIRAGE","Bits":120,"Data":"0x566C0000201A00008C320B233A1061","Repeat":0,"RawData":"+8455-4140+590-555C-1590+585-1595CdFgF-580C-1570ChH-560JdFgFgCdFgCgC-550CdCdFjFdFdFd+610jJdCdFdFjFdCkCdFdFj+600-545+615-530CdCkFjFgFdFjCkFgJfCeCgFdFdFdOpCdCdFdLpCdCdCdCdFdOpFjFdHjFjFdOkJdCgCgOpFdFdF-1600CjFgFdFjFgM-1580FdLpFqFqJhCeFjChJdCdCgFgChJdCdCgFdFdChFiFdFqF-1620JqHjFdFdCdCdFdFgHjLdJdCgLpCdLpFjFqFgFjF","RawDataInfo":[243,243,0]}}
16:55:31.717 MQT: tasmota_38B3E6/tele/RESULT = {"IrReceived":{"Protocol":"MIRAGE","Bits":120,"Data":"0x566C0000201A00008C320B263A1064","Repeat":0,"RawData":"+8455-4140+590-555C-1590+615-1570+585-560CeC-580I-1595CdHiHdHkHkCdHkH-1620IjIdHdHdHiCdHdCdCdHdHiHdHdCdCdHi+610-530HdIjHdMnCdHkC-550HiCdHkMnHkCeCdHdHdCdHiCdCdCoHiHdHiCdCdHdHdHdCdMnCdHdCoHkCkCdHdCdMgHi+640-1545CdHiJkF-1565CdHdHeHkHdHkHdCdMnCdHdCkHkFnCjIeHdHdHdCeHdHkHkCeHdHiCdM-535HdHdHeCdCdCdHdHdHkHdCoCkHkCdH","RawDataInfo":[243,243,0]}}
16:55:38.467 MQT: tasmota_38B3E6/tele/RESULT = {"IrReceived":{"Protocol":"MIRAGE","Bits":120,"Data":"0x566C0000201A00008C320B2E3A106C","Repeat":0,"RawData":"+8450-4135+590-555+585-1595E-1590CdEgC-550CfEdE-580+560dEg+615-1565Ei+565gCfEdEj+610-530EiJdEjEdJiEdJiEjChEdCdEdEdIjChEjEdEhEdN-1570CdChNoCgCdIfCgEjChChEdCdCdEdCdEdEdEjEdEdEjEdEdCdEdEdJeEdNlCgEjEdEdCgCdEfEjChCfEfCdIjIfEfKoEfEdCdEdEdK-525Ef+605pEgEdCgEdEdEdEgCdIfCgEfIjChEdEdEdEdNpEdCdEdEdEdCgCfCdCgEgNoC","RawDataInfo":[243,243,0]}}

as you can see, for the same state (16°C), pressing 3 times the down button, the remote controller will send 3 differents payloads: 0x566C0000201A00008C320B233A1061, 0x566C0000201A00008C320B263A1064, 0x566C0000201A00008C320B2E3A106C

crankyoldgit commented 3 years ago

Looking at the data, it's fairly clear the temperature is stored in the second byte. i.e. state[1] if was captured by IRrecvDumpV2 etc. e.g. 0x6D = 17deg, 0x6E = 18deg. 0x6C = 16deg.

As for why the other digits are changing, as per the wiki that's why we recommend setting the clock to 00:00 etc. They seem to increase/match in a way the timestamps you recorded them. That is, I'm pretty sure its a clock value, with the time values including seconds. This is why we recommend recording a lot of values in a spreadsheet to try to see what changes and what values link to what functions or things.

You are the one that has to do the break-down/analysis/reverse-engineering. We can provide assistance & help etc, but most of the leg work requires your effort.

I strongly suggest you follow that wiki link etc and let us know when you got all the bits that change explained.

akram commented 3 years ago

Thank you for your help and support. Here is a first attempt to capture the data and different states in the following spreadsheet: https://docs.google.com/spreadsheets/d/1Ucu9mOOIIJoWQjUJq_VCvwgV3EwKaRk8K2AuZgccYEk/edit?usp=sharing

I will refine that to break-down the different bytes and states. By reading the Wiki page that you sent, I also understood that the varying bits/bytes are certainly checksum/CRC bits. I put some data into CRC RevEng too with no success for it to guess what is the CRC algorithm being used.

Thanks for your help again, and in the meantime, if you have more advices on how to decode this, as obviously your eye and experience on this in sharper than mine, please feel free to comment.

crankyoldgit commented 3 years ago

Good news, I was about to give up on your checksum value too after I tried a few things, then I got lucky. The alg. is "Sum every nibble (except the last byte/8bits) and that gives you the last byte/8 bits."

e.g. 0x56730000201600000C000C0301003A is: 0x5 + 0x6 + 0x7 + 0x3 + 0x0 + 0x0 + 0x0 + 0x0 + 0x2 + 0x0 + 0x1 + 0x6 + 0x0 + 0x0 + 0x0 + 0x0 + 0x0 + 0xC + 0x0 + 0x0 + 0x0 + 0xC + 0x0 + 0x3 + 0x0 + 0x1 + 0x0 + 0x0 == 0x3A

I've tried it on a few values, and it works.

Also, state[11] (i.e. 4th last byte) looks like it might be a seconds value. For a large number of the values, it seems to track with the timestamp roughly. Also, I never see it go higher than 0x3B (59 dec) which is what we would expect.

The temp seems to be stored in state[1] (i.e. the 2nd byte) e.g. 0x77 is 27degC That is state[1] - 0x5C gives the temp in Celsius. e.g. 0x6E - 0x5C is 18degC

crankyoldgit commented 3 years ago

@akram How are you going with the analysis? Have you got enough of it worked out to do/explain what you want yet?

akram commented 3 years ago

@crankyoldgit I added "Decode" tab in the stylesheet to add bits or snipple signification findings. Until now I was not able to make the AC respond to this. I will continue this evening.

crankyoldgit commented 3 years ago

Cool. The key factors we need to add/support first are Power on/off control & Operation mode. After that, concentrate on Fan Speed. As we already have Temp figured out, you just need those before we can start on adding the beginnings of Detailed support to the library.

crankyoldgit commented 3 years ago

Looking at the data you've collected, a candidate for the operation mode is the 8th nibble (i.e high nibble of state[4]) i.e. https://docs.google.com/spreadsheets/d/1Ucu9mOOIIJoWQjUJq_VCvwgV3EwKaRk8K2AuZgccYEk/edit#gid=380909393&range=D35:D38

crankyoldgit commented 3 years ago

@akram How goes the analysis?

akram commented 3 years ago

@crankyoldgit I think I am almost done with it. There is only the DISPLAY (on/off) and SLEEP(on/off) modes for which I cannot really understand the behaviour. Display on/off seem to be linked with sleep on off; but they are in too separated/distant nibbles.

Also, I still have many nibbles which seems to have fixed value to 0 or C.

What could be the next step to test my assumptions? trying to send IrSend based on these findings ?

crankyoldgit commented 3 years ago

Cool. Good work. I'll look at coding up something based on your Decode sheet soon. I'll let you know when it's ready for some testing. I'm sure I'll have questions as I go.

akram commented 3 years ago

awesome @crankyoldgit , I will be waiting for the update and your questions then.

crankyoldgit commented 3 years ago

What are the Model numbers for your Maxwell A/C and it's remote, please?

akram commented 3 years ago

Remote controller has the following model number on the back: KKG9A-C1 And the AC unit has a label with this number: MX-CH18CF

crankyoldgit commented 3 years ago

Thanks for the rapid response.

akram commented 3 years ago

you're welcome. Things get faster with a proper github notification helper.

In MX-CH18CF , the number 18 seems to be the cooling power of 18k BTU, other less powerfull model have 12 and 9. And CF may refer to Chaud - Froid (Hot and Cool in French) as the device can be used to heat the room also.

I have contacted Maxwell a few months ago, and they seem to have discontinued ACs during covid but they may restart in the future.

crankyoldgit commented 3 years ago

Re: https://docs.google.com/spreadsheets/d/1Ucu9mOOIIJoWQjUJq_VCvwgV3EwKaRk8K2AuZgccYEk/edit#gid=380909393&range=J35:J38

Is there an "Auto" mode? Seems unusual to not have one.

crankyoldgit commented 2 years ago

Also, a big piece of critical info that is missing from your spreadsheet. How is power on/off controlled?!?!

Also I don't see anything for quiet either.

akram commented 2 years ago

Hey @crankyoldgit , So, there is no Auto mode on this one apparently, unless what I interpret as Recycle icon is the auto mode?

Then, regarding Power on/off . I added some captures, and it seems that Power ON does not have a special value, it is only about sending a valid state based on what I have captured.

However, Power Off seems to be adding 0xBE to byte number 5. Thus the whole state is also sent on poweroff.

crankyoldgit commented 2 years ago

Thanks for the updated info. I might make "Recycle" map to "Auto. I'll think about it. Thanks for the power stuff, I'll look at it soon. Please download and test branch: https://github.com/crankyoldgit/IRremoteESP8266/tree/MirageDetailed It should support some of the things you've worked out (No swing or power yet)

Let me know how it goes.

crankyoldgit commented 2 years ago

I think you need to analyse byte[5] more. It doesn't make sense. You may need to look at the bit patterns.

akram commented 2 years ago

I will add more captures to find out the exact behaviour of byte[5].

Regarding QUIET mode, it seems related to nibble[7] (display, sleep) . But also to Fan mode in nibble[9] (fan). Thanks for your great work. I need to find out a way now to build the branch you mentionned and then to build a tasmota-ir version using this version.

akram commented 2 years ago

By adding more captures, I still have this pattern between on an off state:

TURN OFF TEMP=16, FAN=HIGH, SWING=SWIPE

0x566C000021D800000C000C2C230161 16 ON OFF SWIPE COOL OFF HIGH OFF
0x566C000033D800000C000C0424015B 16       DRY      
0x5674000053C400000C000C26240155 N/A       FAN      
0x5674000010D800000C000C3B240159 24       HOT      
0x566C000040D800000C000C3425015D 16       RECYCLE      

TURN ON TEMP=16, FAN=HIGH, SWING=SWIPE

0x566C0000211A00000C000C36270156 16 ON OFF SWIPE COOL OFF HIGH OFF
0x566C0000331A00000C000C0C28015D 16       DRY      
0x56740000530600000C000C2128014A N/A       FAN      
0x56740000101A00000C000C2F280156 24       HOT      
0x566C0000401A00000C000C00290150 16       RECYCLE      

For the first lines of each table, there is always a difference of 0xBE between D8 and 1A for instance. And same applies for the others.

crankyoldgit commented 2 years ago

I've updated that branch with support for power control. e.g. setPower()/getPower() etc

crankyoldgit commented 2 years ago

Can you please expand on https://docs.google.com/spreadsheets/d/1Ucu9mOOIIJoWQjUJq_VCvwgV3EwKaRk8K2AuZgccYEk/edit#gid=380909393&range=J43:J50

Swing Position:
1A = Swipe
0A = Vertical High
16 = Horizontal
12 = Horizontal Low
0E = Diagonal
06 = Vertical High

Turn OFF = Add 0xBE to byte #5
  1. You've got two "Vertical High"s.
  2. Does "Swipe" mean swing "side to side", or "up & down"?
  3. Is Diagonal swing/swipe in both Vertical & Horizontal simultaneously?
  4. Can you give a more detailed explanations of the swing modes/positions/descriptions?

I need to map these to "common" swing modes such as: https://github.com/crankyoldgit/IRremoteESP8266/blob/ca44fa33bbe872c8b646e6c7be4b270968268bd7/src/IRsend.h#L69-L94

Thanks in advance.

akram commented 2 years ago

My answers inline:

1. You've got two "Vertical High"s.

I now fixed that and I also used the terminology of IRSend.h ; and set them into ascending order. auto is the latest, and it matches with natural values ordering.

2. Does "Swipe" mean swing "side to side", or "up & down"?

Swipe is actually auto, and this unit has only vertical (up & down) swinging; no side to side.

3. Is _Diagonal_ swing/swipe in both Vertical & Horizontal simultaneously?

Diagonal was actually middle.

4. Can you give a more detailed explanations of the swing modes/positions/descriptions?

That should help.

So values are: Swing Positions:

06 = lowest
0A = low
0E = middle
12 = high
16 = highest
1A = auto

Setting swing to OFF does not seem possible on this unit, but, when enabling turbo mode, the Remote Controller shows that swing is blocked into low position, so I would map swingv_t.kOff to 4 (kLow).

crankyoldgit commented 2 years ago

I've updated the branch again with Swing Support. Please download & test.

Also, can you please test using the IRrecvDumpV2+ programs, rather than Tasmota. It will give me far more helpful data. e.g. It will list values as UNKNOWN etc when it encounters something unexpected. I'm not sure Tasmota will do that.

I've found some captured data where byte[5] is 0x01 which doesn't fit with your explainations/descriptions.

I think only the top (MSBs) 7 bits of byte[5] contain swing/power data. It could even be less. e.g. the second least significant bit could actually be one of the power bits.

When you look at the values you've suggested:

const uint8_t kMirageAcSwingVLowest =   0b00110;  // 6
const uint8_t kMirageAcSwingVLow =      0b01010;  // 10
const uint8_t kMirageAcSwingVMiddle =   0b01110;  // 14
const uint8_t kMirageAcSwingVHigh =     0b10010;  // 18
const uint8_t kMirageAcSwingVHighest =  0b10110;  // 22
const uint8_t kMirageAcSwingVAuto =     0b11010;  // 26

You can see the least significant bit is unused. Using the "power" plus/minus value of 0xBE won't affect that bit. Hence I think that bit is unused/unknown.

If you remove that bit (and change the power plus/minus value to 0x5F) you get:

const uint8_t kMirageAcSwingVLowest =   0b0011;  // 3
const uint8_t kMirageAcSwingVLow =      0b0101;  // 5
const uint8_t kMirageAcSwingVMiddle =   0b0111;  // 7
const uint8_t kMirageAcSwingVHigh =     0b1001;  // 9
const uint8_t kMirageAcSwingVHighest =  0b1011;  // 11
const uint8_t kMirageAcSwingVAuto =     0b1101;  // 13

Which works fine with in the tests I've run.

However, looking at it, you can see the last bit is always 1. Which I think is (one of) the power bit. You also get a nice sequence of values for the swing settings. e.g.

const uint8_t kMirageAcSwingVLowest =   0b001;  // 1
const uint8_t kMirageAcSwingVLow =      0b010;  // 2
const uint8_t kMirageAcSwingVMiddle =   0b011;  // 3
const uint8_t kMirageAcSwingVHigh =     0b100;  // 4
const uint8_t kMirageAcSwingVHighest =  0b101;  // 5
const uint8_t kMirageAcSwingVAuto =     0b110;  // 6

This is why I suggested you take a longer/deeper look at byte[5]'s contents.

akram commented 2 years ago

Ok awesome @crankyoldgit , I will be able to look at it only at my evening time now (in 8hours from now or so) and during the week-end. Then, I don't have any other choice than using tasmota right now :-(, cause I can't easily get the parts to build IRrecvDumpV2 compatible device, so I will do my best with tasmota and tell you then.

akram commented 2 years ago

hey @crankyoldgit , I have succesfully compiled a tasmota version with the content of the forementionned branch. And I deployed it succesfully on my device. However, my tests are not making anything new. I am actually only using IRSend command on tasmota. Should I use IRHVAC commands instead? If yes, then, I need to figure out how to enable MIRAGE vendor as it is not recognized by tasmota.

If you have any help or suggestions I am all ears.

crankyoldgit commented 2 years ago

Should I use IRHVAC commands instead?

Yes, to use the new features of MIRAGE you will need to use it via IRHVAC as I understand it.

If yes, then, I need to figure out how to enable MIRAGE vendor as it is not recognized by tasmota.

I thought it was automatic, but that is beyond my knowledge. You'll have to check with the Tasmota team.

crankyoldgit commented 2 years ago

@akram Friendly chase up.

crankyoldgit commented 2 years ago

Another chase up. We are waiting on your feedback before we merge the support into the library.

akram commented 2 years ago

Hi @crankyoldgit , I will have a look at it between tomorrow and today during my week-end. My last tries were not succesful, I managed to build a custom tasmota version but I am pretty sure that the default tasmota ir firmware disables some IRhvac protocols to save space during firmware compilation.

I will have to go with a custom ir firmware and that required be more investigations.

crankyoldgit commented 2 years ago

Yes, I think you want to build tasmota-ir as it includes/enables all the IR protocols. The standard one only enables a handful of protocols.

See: https://github.com/arendst/Tasmota/blob/9b329a031a47f2566012392e60811bd370821fbb/platformio_tasmota_env.ini#L57-L59 https://tasmota.github.io/docs/Compile-your-build/ https://tasmota.github.io/docs/Tasmota-IR/

akram commented 2 years ago

This is what I followed and used a docker image provided by one of the contributors to compile my own firmware. I will restart that process by the week-end.

crankyoldgit commented 2 years ago

Any luck?

crankyoldgit commented 2 years ago

Another chase up. If we don't get confirmation either way from you soon, we will assume it's fine and merge the PR.

crankyoldgit commented 2 years ago

Giving up, and merging what we have. Assuming it is work. Please open a new issue if it isn't.

akram commented 2 years ago

Hi @crankyoldgit , thanks for your patience. I wasn't able to succesfully test it. In a few months, I could give another try when the tasmota team will update to an earlier version. And that time, I will have more hardware to test.

dschulte commented 2 years ago

Hi, I recently bought a Tronitechnik AC (link) which is identified as Mirage. I have a test circuit on hand so I can use IRrecvDumpV2. My remote model is "KKG29A-C1" (pictures) I'm relatively sure that there are some differences as my remote seems not to have a clock as these values stay at zero and some other values differ.

At the moment I can confirm temperature, mode ("recycle" is probably auto mode).

The rest differs a lot. My findings are:

Fan speed differs: // low 0b10 // med 0b11 // high 0b01 // auto 0b00

byte 3: xxxxxxx1: quiet mode

byte 5: 11xxxxxx: power off 00xxxxxx: power on xxxxx1xx: display (back to 0 on next message if not pressed again) xxxxxxx1: h-sweep xxxxxx1x: v-sweep

byte 6: x1xxxxxx: is set in "recycle" and heat mode; probably something heat related xxxx1xxx: sleep xxxxxx1x: UVC

byte 7: x1xxxxxx: clean (back to 0 on next message if not pressed again)

byte 8: 1xxxxxxx: turbo

There is also an "I Feel" mode, where the remote senses the room temperature. I really want to get this mode working as I can then regulate the AC way more precise. AFAIK this is managed completely in byte 7. I'll get back later in some days with some dumps. As the measured temp is displayed in the remote, this should be fairly easy to decode. Everything should be taken with a grain of salt by now as I haven't confirmed every bit in every mode yet.

It seems that there are huge differences to the current implementation. Should these changes go to a new model? What is the desired practice? Is there anything else I can do to help?

dschulte commented 2 years ago

Ok, that was easier than expected. byte 7 is as follows: 1xxxxxxx: i feel mode on x1xxxxxx: clean (back to 0 on next message if not pressed again) xx111111: remote temperature (111111-> 43C, 010100 -> 0C; so actual value with offset of 20DEC)

Some example data from (modified) IRrecvDumpV2: Mode heat, 24C, fan speed low

// i feel on 43C (max)
uint8_t state[15]    = {0x56    , 0x74    , 0x00    , 0x00    , 0x12    , 0x00    , 0x40    , 0x3F    , 0x00    , 0x00    , 0x00    , 0x00    , 0x00    , 0x00    , 0x2F    };
uint8_t stateBin[15] = {01010110, 01110100, 00000000, 00000000, 00010010, 00000000, 01000000, 00111111, 00000000, 00000000, 00000000, 00000000, 00000000, 00000000, 00101111};

uint8_t state[15]    = {0x56    , 0x74    , 0x00    , 0x00    , 0x12    , 0x00    , 0x40    , 0xBF    , 0x00    , 0x00    , 0x00    , 0x00    , 0x00    , 0x00    , 0x37    };
uint8_t stateBin[15] = {01010110, 01110100, 00000000, 00000000, 00010010, 00000000, 01000000, 10111111, 00000000, 00000000, 00000000, 00000000, 00000000, 00000000, 00110111};

// i feel off
uint8_t state[15]    = {0x56    , 0x74    , 0x00    , 0x00    , 0x12    , 0x00    , 0x40    , 0x00    , 0x00    , 0x00    , 0x00    , 0x00    , 0x00    , 0x00    , 0x1D    };
uint8_t stateBin[15] = {01010110, 01110100, 00000000, 00000000, 00010010, 00000000, 01000000, 00000000, 00000000, 00000000, 00000000, 00000000, 00000000, 00000000, 00011101};

// i feel on 0C (min)
uint8_t state[15]    = {0x56    , 0x74    , 0x00    , 0x00    , 0x12    , 0x00    , 0x40    , 0x14    , 0x00    , 0x00    , 0x00    , 0x00    , 0x00    , 0x00    , 0x22    };
uint8_t stateBin[15] = {01010110, 01110100, 00000000, 00000000, 00010010, 00000000, 01000000, 00010100, 00000000, 00000000, 00000000, 00000000, 00000000, 00000000, 00100010};

uint8_t state[15]    = {0x56    , 0x74    , 0x00    , 0x00    , 0x12    , 0x00    , 0x40    , 0x94    , 0x00    , 0x00    , 0x00    , 0x00    , 0x00    , 0x00    , 0x2A    };
uint8_t stateBin[15] = {01010110, 01110100, 00000000, 00000000, 00010010, 00000000, 01000000, 10010100, 00000000, 00000000, 00000000, 00000000, 00000000, 00000000, 00101010};

// i feel off
uint8_t state[15]    = {0x56    , 0x74    , 0x00    , 0x00    , 0x12    , 0x00    , 0x40    , 0x00    , 0x00    , 0x00    , 0x00    , 0x00    , 0x00    , 0x00    , 0x1D    };
uint8_t stateBin[15] = {01010110, 01110100, 00000000, 00000000, 00010010, 00000000, 01000000, 00000000, 00000000, 00000000, 00000000, 00000000, 00000000, 00000000, 00011101};

// i feel on, 9C
uint8_t state[15]    = {0x56    , 0x74    , 0x00    , 0x00    , 0x12    , 0x00    , 0x40    , 0x1D    , 0x00    , 0x00    , 0x00    , 0x00    , 0x00    , 0x00    , 0x2B    };
uint8_t stateBin[15] = {01010110, 01110100, 00000000, 00000000, 00010010, 00000000, 01000000, 00011101, 00000000, 00000000, 00000000, 00000000, 00000000, 00000000, 00101011};

uint8_t state[15]    = {0x56    , 0x74    , 0x00    , 0x00    , 0x12    , 0x00    , 0x40    , 0x9D    , 0x00    , 0x00    , 0x00    , 0x00    , 0x00    , 0x00    , 0x33    };
uint8_t stateBin[15] = {01010110, 01110100, 00000000, 00000000, 00010010, 00000000, 01000000, 10011101, 00000000, 00000000, 00000000, 00000000, 00000000, 00000000, 00110011};
dschulte commented 2 years ago

Last post for today... This is the almost completely decoded message. All button presses produce a distinct change in the message. There is a small uncertainty with the on/off timers when set to 24h which shouldn't cause any problems.

The message format is really simple so it seems that the remote from the OP is different. So... What to do next?

byte 0
01010110: header (0x56)

byte 1
temperature offset 0x5c

byte 2
00000000: unknown

byte 3
xxxxxxx1: quiet mode
0000000x: unknown

byte 4
x111xxxx: mode
xxxx1xxx: timer on
xxxxx1xx: timer off
xxxxxx11: fan speed
0xxxxxxx: unknown

byte 5
11xxxxxx: power off (11); power on (00)
xxxxx1xx: display (back to 0 in next message if not pressed again)
xxxxxx1x: v-sweep
xxxxxxx1: h-sweep
xx000xxx: unknown

byte 6
x1xxxxxx: is set in "recycle" and heat mode; probably something heat related
xxxx1xxx: sleep
xxxxxx1x: UVC
0x00x0x0: unknown

byte 7
1xxxxxxx: i feel mode
x1xxxxxx: clean (back to 0 in next message if not pressed again)
xx111111: i feel remote temperature (111111-> 43C, 010100 -> 0C; so actual value with offset of 20DEC)

byte 8
1xxxxxxx: turbo
xxx10111: on timer 00001->1h, 10111->24h
x00xxxxx: unknown

byte 9
00111011: unclear, changes while off timer runs

byte 10
xxx10111: off timer 00001->1h, 10111->24h

byte 11
00111011: unclear, changes while on timer runs

byte 12
00000000: unknown

byte 13
00000000: unknown

byte 14
checksum
crankyoldgit commented 2 years ago

Last post for today... This is the almost completely decoded message. All button presses produce a distinct change in the message. There is a small uncertainty with the on/off timers when set to 24h which shouldn't cause any problems.

The message format is really simple so it seems that the remote from the OP is different. So... What to do next?

Thanks for the detailed data & analysis so far.

I'm assuming this is being detected a MIRAGE. Our first goal, is to see if we can find anything to tell the two models apart. That could be a difference in the timing signals (can you provide a rawData[] from your remote please?), or something in the state[] that allows us to tell between the two formats. e.g. Maybe state[8] second MSB i.e. (0bx1xxxxxx) as it's 0xC0/0b11000000 all the time in the one we have coded up, you seem to indicate that bit is always 0 in yours.

Anyway. We need to find something reliable to tell the two apart if possible. Can you see what else you can find, the more the better?

Once we have that, I can try to implement different model support. Depending how much they share, it may be implemented in the same class, or I might make it two different classes.

BTW, what does UVC stand for?

dschulte commented 2 years ago

Mode heat, 24C, fan speed low

Timestamp : 000012.949
Library   : v2.7.20

Protocol  : MIRAGE
Code      : 0x56740000120040000000000000001D (120 Bits)
Mesg Desc.: Power: On, Mode: 1 (Heat), Temp: 24C, Fan: 2 (Medium), Swing(V): 0 (UNKNOWN), Turbo: Off, Light: Off, Sleep: Off, Clock: 00:00
uint16_t rawData[243] = {8354, 4214,  526, 564,  526, 1634,  528, 1632,  528, 560,  528, 1636,  526, 562,  526, 1636,  526, 560,  528, 560,  526, 562,  528, 1634,  526, 560,  528, 1632,  530, 1634,  526, 1634,  528, 562,  526, 562,  524, 562,  526, 560,  532, 558,  530, 558,  528, 560,  528, 562,  526, 562,  526, 560,  528, 560,  528, 560,  528, 560,  528, 560,  526, 560,  528, 562,  530, 558,  524, 562,  528, 1634,  524, 562,  528, 560,  528, 1634,  528, 560,  528, 562,  528, 560,  526, 562,  526, 562,  526, 560,  526, 560,  528, 560,  526, 562,  526, 562,  524, 562,  526, 562,  526, 560,  526, 562,  528, 560,  526, 560,  526, 564,  524, 1636,  524, 564,  526, 562,  528, 562,  524, 560,  528, 560,  526, 562,  528, 560,  526, 560,  528, 562,  526, 562,  528, 562,  524, 562,  528, 560,  526, 560,  526, 564,  524, 562,  528, 562,  526, 560,  526, 566,  524, 560,  528, 560,  526, 560,  530, 560,  526, 566,  522, 562,  524, 562,  528, 560,  526, 562,  528, 562,  526, 562,  526, 562,  524, 562,  524, 564,  524, 562,  526, 560,  526, 562,  526, 562,  526, 564,  524, 560,  528, 560,  526, 562,  526, 564,  524, 562,  526, 560,  526, 566,  522, 562,  526, 560,  528, 558,  528, 560,  530, 558,  528, 560,  528, 560,  528, 560,  526, 562,  526, 562,  526, 562,  526, 560,  528, 1634,  528, 560,  528, 1634,  526, 1634,  530, 1632,  528, 560,  528, 560,  528, 560,  526};  // MIRAGE
uint8_t state[15]    = {0x56   0, 0x74   1, 0x00   2, 0x00   3, 0x12   4, 0x00   5, 0x40   6, 0x00   7, 0x00   8, 0x00   9, 0x00  10, 0x00  11, 0x00  12, 0x00  13, 0x1D  14};
uint8_t stateBin[15] = {01010110, 01110100, 00000000, 00000000, 00010010, 00000000, 01000000, 00000000, 00000000, 00000000, 00000000, 00000000, 00000000, 00000000, 00011101};

All unknown bits stay at 0. If there are bits in the other model that are always 1, this might be an okayish differentiation. I don't have much knowledge about IR protocols yet. So I don't know if this is a feasible soulution.

UVC is a UV-C light in the unit which should kill bacteria and such things.

crankyoldgit commented 2 years ago

Thanks for that. Unfortunately, we can't use timings it seems to differentiate the protocols. So, it's down to guesses with bits in the state[]. I'll try to work something out.

Re: UVC. We have two common features in the IRac class representation for generic A/Cs. clean & filter. You've already defined clean in your analysis. Should we use the UVC setting for filter or for clean? Technically this doesn't matter, and I suspect filter is the better choice here, but you're the one with the manual and the device, so I'm letting you make that call. ;-) Typically clean is the least used option by a typical user. filter is more commonly used day-to-day. e.g. Ion filter/dust filter/mould filter/etc.

dschulte commented 2 years ago

Then probably filter for UVC is suitable as there is also a clean button which obviously should be mapped to clean. UVC is kind of a filter as it filters out bacteria by destroying them.

crankyoldgit commented 2 years ago

Hi, I recently bought a Tronitechnik AC (link)

Is there a model number/code for the device?

crankyoldgit commented 2 years ago

byte 9 00111011: unclear, changes while off timer runs

byte 10 xxx10111: off timer 00001->1h, 10111->24h

byte 11 00111011: unclear, changes while on timer runs

FYI, 0b00111011 is 59 (dec). It's most likely the minutes value for the timer(s)

crankyoldgit commented 2 years ago

// i feel on 43C (max) uint8_t state[15] = {0x56 , 0x74 , 0x00 , 0x00 , 0x12 , 0x00 , 0x40 , 0x3F , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x2F }; uint8_t stateBin[15] = {01010110, 01110100, 00000000, 00000000, 00010010, 00000000, 01000000, 00111111, 00000000, 00000000, 00000000, 00000000, 00000000, 00000000, 00101111};

uint8_t state[15] = {0x56 , 0x74 , 0x00 , 0x00 , 0x12 , 0x00 , 0x40 , 0xBF , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x37 }; uint8_t stateBin[15] = {01010110, 01110100, 00000000, 00000000, 00010010, 00000000, 01000000, 10111111, 00000000, 00000000, 00000000, 00000000, 00000000, 00000000, 00110111};

What is with the two state[]s? And why are they different? It looks like the IFeel bit is set on the latter one, but why not on the first one, when I assume the IFeel but is being pressed?