Hacking Electrolux Smart AC

Haha, I had just come across that myself, updated env and got:

(.venv) REDACTED@MacBook-Air ac_mqtt % python3 monitor.py -S
/Users/REDACTED/Documents/ac_mqtt/monitor.py v1.1.0 is starting up
Loglevel set to DEBUG
Binding to ip 192.168.1.226
Recieved response! devtype: 20379 mac: bytearray(b'$\xdf\xa7K\xbco') name: ELECTROLUX_OEM host: ('192.168.1.145', 80) cloud: False
Debugging Enabled
Authenticating
Setting test temperature
Setting temprature to 25
Start set_ac_status
Resposnse:5aa5aa555aa5aa55000000000000000000000000000000000000000000000000f3d3fbff2a4eee03425824dfa74bbc6f01000000afbe0000ec824b547c9e6bf54c1321fa4ae4d7b7
Getting current details in init
device: <broadlink_ac_mqtt.classes.broadlink.ac_db.ac_db_debug object at 0x7f91a81efd00> device.devtype: 0x4f9b
Returning devices: {'24dfa74bbc6f': <broadlink_ac_mqtt.classes.broadlink.ac_db.ac_db_debug object at 0x7f91a81efd00>}
*********** start copy below ************
devices:
- ip: 192.168.1.145
  mac: 24dfa74bbc6f
  name: !!binary |
    RUxFQ1RST0xVWF9PRU0=
  port: 80

*********** stop copy above ************

@TJohnson93, you have REDACTED that much, that I have no clue that does it working or not at the end…

The “Resposnse:” line would be interesting…

By the way has it managed to set the temperature to 25?

Was probably being too pedantic, given up on that, see edited comment… and no it didn’t publishing something with the MAC as well didn’t get very far.

EDIT: What is interesting is that I can’t see the communication over MQTT explorer either (pointing at HA)…

Do you have 2 units? The two responses what you posted have two different device types.

Have you updated the type in the that class as well? As I looked at quickly, it uses it for the communication.

Ah Sorry, yeah, I have a Broadlink RM Pro that’s the first one. EDIT: I’ve updated everywhere where it’s listed as 4E2A

It is listed as 2a and 4e… in the

def send_packet(self, command, payload):
        self.count = (self.count + 1) & 0xffff
        packet = bytearray(0x38)
        packet[0x00] = 0x5a
        packet[0x01] = 0xa5
        packet[0x02] = 0xaa
        packet[0x03] = 0x55
        packet[0x04] = 0x5a
        packet[0x05] = 0xa5
        packet[0x06] = 0xaa
        packet[0x07] = 0x55
        packet[0x24] = 0x2a  # ==> Type
        packet[0x25] = 0x4e  # ==> Type
        packet[0x26] = command
        packet[0x28] = self.count & 0xff
        packet[0x29] = self.count >> 8
        packet[0x2a] = self.mac[0]
        packet[0x2b] = self.mac[1]
        packet[0x2c] = self.mac[2]
        packet[0x2d] = self.mac[3]
        packet[0x2e] = self.mac[4]
        packet[0x2f] = self.mac[5]
        packet[0x30] = self.id[0]
        packet[0x31] = self.id[1]
        packet[0x32] = self.id[2]
        packet[0x33] = self.id[3]

Updated:

# packet[0x24] = 0x2a  # ==> Type
# packet[0x25] = 0x4e  # ==> Type
packet[0x24] = 0x9b  # ==> Type
packet[0x25] = 0x4f  # ==> Type
(.venv) REDACTED@MacBook-Air ac_mqtt % python3 monitor.py
/Users/REDACTED/Documents/ac_mqtt/monitor.py v1.1.0 is starting up
Loglevel set to DEBUG
Checking if already running
Starting Monitor...
Starting mainloop, responding on only events
Coneccting to MQTT: 192.168.1.231 with client ID = ac_to_mqtt
Debugging Enabled
Authenticating
Mqtt connected! client=<paho.mqtt.client.Client object at 0x7fd6b002d7c0>, userdata=None, flags={'session present': 0}, rc=0
Listing on aircons/+/+/set for messages
publishing on topic "aircons/LWT", data "online"
Setting test temperature
Setting temprature to 25
Start set_ac_status
Resposnse:5aa5aa555aa5aa55000000000000000000000000000000000000000000000000e6d4fbff9b4fee03eb3024dfa74bbc6f01000000afbe0000ec824b547c9e6bf54c1321fa4ae4d7b7
Getting current details in init
device: <broadlink_ac_mqtt.classes.broadlink.ac_db.ac_db_debug object at 0x7fd6e0311e20>
Traceback (most recent call last):
  File "/Users/REDACTED/Documents/ac_mqtt/monitor.py", line 364, in start
    AC.publish_mqtt_auto_discovery(devices)
  File "/Users/REDACTED/Documents/ac_mqtt/broadlink_ac_mqtt/AcToMqtt.py", line 261, in publish_mqtt_auto_discovery
    devices_array = self.make_devices_array_from_devices(devices)
  File "/Users/REDACTED/Documents/ac_mqtt/broadlink_ac_mqtt/AcToMqtt.py", line 193, in make_devices_array_from_devices
    name = device.name.encode("ascii", "ignore")
AttributeError: 'bytes' object has no attribute 'encode'

'bytes' object has no attribute 'encode'
Stopping

Have you tried this?

Being a BroadLink device you can try to get temperature and humidity first. And maybe control power on and off.

And you can have a better understanding what is going on.

I hadn’t, just tried it though, the discovery works fine:

(.venv) REDACTED@MacBook-Air ac_mqtt % python3 broadlink_discovery.py
Discovering...
###########################################
Unknown
# broadlink_cli --type 0x4f9b --host 192.168.1.145 --mac 24dfa74bbc6f
Device file data (to be used with --device @filename in broadlink_cli) :
0x4f9b 192.168.1.145 24dfa74bbc6f

However there must be different commands to control

(.venv) REDACTED@MacBook-Air ac_mqtt % python3 broadlink_cli.py --type 0x4f9b --host 192.168.1.145 --mac 24dfa74bbc6f --turnoff
Traceback (most recent call last):
  File "/Users/REDACTED/Documents/ac_mqtt/broadlink_cli.py", line 174, in <module>
    dev.set_power(False)
AttributeError: 'Device' object has no attribute 'set_power'

EDIT: Looks like HEX, based on the ac_mqtt code:

def get_ac_states(self, force_update=False):
        # From app queryAuxinfo:bb0006800000020011012b7e
        GET_STATES = bytearray.fromhex("0C00BB0006800000020011012B7E0000")

Temperature? Humidity?

A good start so far…

Need to add more logging to the AC get status code to see what is happening there.

Maybe decompile the Android app and dig into that for device type specific thing.

I don’t expect that they change too much between device types. It is far more easier to reuse code than to build new.

Looks like there is a data flag, just not sure on the data required in there yet.

I’ve got some more info with the acmqtt method:

2022-01-10 19:07:18,263,263 DEBUG    [monitor.py:290] /Users/toddjohnson/Documents/ac_mqtt/monitor.py v1.1.0 is starting up
2022-01-10 19:07:18,265,265 DEBUG    [monitor.py:293] Loglevel set to DEBUG
2022-01-10 19:07:18,267,267 DEBUG    [monitor.py:132] Checking if already running
2022-01-10 19:07:18,267,267 INFO     [monitor.py:346] Starting Monitor...
2022-01-10 19:07:18,267,267 DEBUG    [monitor.py:348] Starting mainloop, responding on only events
2022-01-10 19:07:18,267,267 DEBUG    [AcToMqtt.py:370] Coneccting to MQTT: 192.168.1.231 with client ID = ac_to_mqtt
2022-01-10 19:07:18,296,296 DEBUG    [ac_db.py:42] Binding to ip 192.168.1.226
2022-01-10 19:07:18,305,305 DEBUG    [AcToMqtt.py:579] Mqtt connected! client=<paho.mqtt.client.Client object at 0x7fcd18077cd0>, userdata=None, flags={'session present': 0}, rc=0
2022-01-10 19:07:18,305,305 DEBUG    [AcToMqtt.py:587] Listing on aircons/+/+/set for messages
2022-01-10 19:07:18,305,305 DEBUG    [AcToMqtt.py:339] publishing on topic "aircons/LWT", data "online"
2022-01-10 19:07:18,347,347 DEBUG    [ac_db.py:126] Recieved response! devtype: 20379 mac: bytearray(b'$\xdf\xa7K\xbco') name: ELECTROLUX_OEM host: ('192.168.1.145', 80) cloud: False
2022-01-10 19:07:18,347,347 DEBUG    [ac_db.py:933] Debugging Enabled
2022-01-10 19:07:18,347,347 DEBUG    [ac_db.py:935] Authenticating
2022-01-10 19:07:18,443,443 DEBUG    [ac_db.py:939] Setting test temperature
2022-01-10 19:07:18,443,443 DEBUG    [ac_db.py:1032] Setting temprature to 25
2022-01-10 19:07:18,443,443 DEBUG    [ac_db.py:1040] Start set_ac_status
2022-01-10 19:07:18,446,446 DEBUG    [ac_db.py:1111] Resposnse:5aa5aa555aa5aa5500000000000000000000000000000000000000000000000040d4fbff9b4fee036d0824dfa74bbc6f01000000afbe0000ec824b547c9e6bf54c1321fa4ae4d7b7
2022-01-10 19:07:18,446,446 DEBUG    [ac_db.py:943] Getting current details in init
2022-01-10 19:07:23,299,299 DEBUG    [AcToMqtt.py:63] device: <broadlink_ac_mqtt.classes.broadlink.ac_db.ac_db_debug object at 0x7fcd2844e9a0> device.devtype: 0x4f9b
2022-01-10 19:07:23,300,300 DEBUG    [AcToMqtt.py:69] Returning devices: {'24dfa74bbc6f': <broadlink_ac_mqtt.classes.broadlink.ac_db.ac_db_debug object at 0x7fcd2844e9a0>}
2022-01-10 19:07:23,300,300 DEBUG    [AcToMqtt.py:187] device: <broadlink_ac_mqtt.classes.broadlink.ac_db.ac_db_debug object at 0x7fcd2844e9a0>
2022-01-10 19:07:23,300,300 DEBUG    [AcToMqtt.py:273] HA config Retain set to: True
2022-01-10 19:07:23,301,301 DEBUG    [AcToMqtt.py:339] publishing on topic "homeassistant/climate/24dfa74bbc6f/config", data "{"name": "ELECTROLUX_OEM", "mode_command_topic": "aircons/24dfa74bbc6f/mode_homeassistant/set", "temperature_command_topic": "aircons/24dfa74bbc6f/temp/set", "fan_mode_command_topic": "aircons/24dfa74bbc6f/fanspeed_homeassistant/set", "action_topic": "aircons/24dfa74bbc6f/homeassistant/set", "current_temperature_topic": "aircons/24dfa74bbc6f/ambient_temp/value", "mode_state_topic": "aircons/24dfa74bbc6f/mode_homeassistant/value", "temperature_state_topic": "aircons/24dfa74bbc6f/temp/value", "fan_mode_state_topic": "aircons/24dfa74bbc6f/fanspeed_homeassistant/value", "fan_modes": ["Auto", "Low", "Medium", "High", "Turbo", "Mute"], "modes": ["off", "cool", "heat", "fan_only", "dry"], "max_temp": 32.0, "min_temp": 16.0, "precision": 0.5, "temp_step": 0.5, "unique_id": "24dfa74bbc6f", "device": {"ids": "24dfa74bbc6f", "name": "ELECTROLUX_OEM", "model": "Aircon", "mf": "Broadlink", "sw": "1.1.3"}, "pl_avail": "online", "pl_not_avail": "offline", "availability_topic": "aircons/LWT"}"
2022-01-10 19:07:23,302,302 DEBUG    [AcToMqtt.py:113] Following devices configured {'24dfa74bbc6f': <broadlink_ac_mqtt.classes.broadlink.ac_db.ac_db_debug object at 0x7fcd2844e9a0>}
2022-01-10 19:07:23,303,303 CRITICAL [AcToMqtt.py:153] 'ac_db_debug' object has no attribute 'get_ac_status'
2022-01-10 19:07:23,306,306 DEBUG    [AcToMqtt.py:154] Traceback (most recent call last):
  File "/Users/toddjohnson/Documents/ac_mqtt/broadlink_ac_mqtt/AcToMqtt.py", line 142, in start
    status = device.get_ac_status()
AttributeError: 'ac_db_debug' object has no attribute 'get_ac_status'

Here should be a debug log from the get_ac_states, just after the set_temperature.

Something is not right there.

The function doesn’t actually do any formal checks so unless it breaks something, command is probably sent but nothing receives or bounces without error:

def set_temperature(self, temperature):
        self.logger.debug("Setting temprature to %s", temperature)
        # self.get_ac_states()
        self.status['temp'] = float(temperature)

        self.set_ac_status()
        # return self.make_nice_status(self.status)

It also returns nothing.

It just returns all the statuses in status, which otherwise empty if err !=0. So it gives the point where to search for the issues with the response.

And after it uses the status if any in the set_ac_status

And you can log the status as well for more understanding what is returned.

Found a few interesting links:

I was reading a bit more about it, and the states what it receives from the AC, it sends it back to it when there is a control change. So the get_ac_states is essentially for the operation.

Yeah, stumbled across the same. So for broadlink wifi climate devices. It sends all the commands at once, so this is trying to get current state,.edit a single command and send the whole lot back again. Unfortunately I haven’t had much time to dive deeper over last couple of day, hoping to get some more done throughout the week.

Hey all - I’ve been following this thread for a while. Pardon the interruption, but I believe this is the same API that the Frigidaire Gallery smart AC units use (I have 3 of these units).

When I looked at the web traffic from my Frigidaire 2.0 iphone app, it was an api.electrolux looking URL.

My hope is that the findings here can be used to hack the Frigidaire units as well. If you need any testing or logs for that let me know :slight_smile:

Keep up the good work!

Can you try to use the Broadlink CLI what I posted above and do a discovery on it to see that what device type is it using?

This:

I’ve tried to manually decode this response, but there is a problem. At byte 22 and 23 there should be 00 and 00, but you have fb and ff. So, I guess that the command to get the status is incorrect. (That is written in the python-broadlink protocol.md file.)

So as the query for the states is starting with a command extracted from the app, queryAuxinfo, it could be that is different for this device type.

Somehow queryAuxinfo should be extracted from your app to get the right command.

Edit:

The other thing to support the description of the responses, it would be great to log the encryption key after authentication.

You can give a few tries before posting anything that the encryption key is changing after each authentication or not.

The other thing related the queryAuxinfo, the Hysen class uses a 6 byte command (but that one is a thermostat), meanwhile the code (AC) uses a 16 byte long for the info and 23 for the changes. (If I counted correctly.)