Skip to content

Commit

Permalink
Add command structure + packet builder + status command
Browse files Browse the repository at this point in the history
  • Loading branch information
Balazs Nadasdi committed Apr 22, 2018
1 parent 2df19c3 commit f5f991a
Show file tree
Hide file tree
Showing 9 changed files with 149 additions and 9 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
### CRC Table + base64

I tried to generate the crc8 table, but I can't.
The table itself is a very long one,
so I packed base64 encoded it.

At least this one is not working:

Expand Down Expand Up @@ -50,4 +54,4 @@ crc8_854_table = [
0x74, 0x2A, 0xC8, 0x96, 0x15, 0x4B, 0xA9, 0xF7,
0xB6, 0xE8, 0x0A, 0x54, 0xD7, 0x89, 0x6B, 0x35
]
```
```
18 changes: 15 additions & 3 deletions lib/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,10 @@ def appliance_list
response['list']
end

private

def appliance_transparent_send(appliance_id, data)
response = api_request(
'appliance/transparent/send',
order: encode(Security.transcode(data).join(',')),
order: encode(@security.transcode(data).join(',')),
funId: '0000',
applianceId: appliance_id
)
Expand All @@ -61,6 +59,20 @@ def appliance_transparent_send(appliance_id, data)
response
end

def new_packet_builder
PacketBuilder.new(@security)
end

private

def encode(data)
@security.aes_encrypt(data, @security.data_key)
end

def decode(data)
@security.aes_decrypt(data, @security.data_key)
end

def api_request(endpoint, **args)
args = {
appId: @app_id, format: FORMAT, clientType: CLIENT_TYPE,
Expand Down
33 changes: 33 additions & 0 deletions lib/commands/command.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
module MideaAirCondition
module Command
# Base Command class
class BaseCommand
# Default device type: 0xAC
def initialize(device_type: 0xAC)
@data = [0xaa, 0x23, device_type, 0x00, 0x00, 0x00, 0x00, 0x00]

@data += [
0x03, 0x02, 0xff, 0x81, 0x00, 0xff, 0x03, 0xff,
0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
]

fill
end

def finalize(security)
# Add command sequence number
# Can't be lower than 3
@data << 0x03
@data << security.crc8(@data[0x10..(@data.length - 1)])
@data[0x01] = @data.length

@data
end

private

def fill; end
end
end
end
10 changes: 10 additions & 0 deletions lib/commands/request_status.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module MideaAirCondition
module Command
# Request status of a device
class RequestStatus < BaseCommand
def fill
@data[0x0a] = 0x40
end
end
end
end
19 changes: 19 additions & 0 deletions lib/commands/set.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module MideaAirCondition
module Command
# Request status of a device
class Set < BaseCommand
def turn_on
@data[0x3] |= 0x1
end

def turn_off
@data[0x3] &= 0x1
end

def temperature=(celsius, mode: 2)
c = ((mode << 5) & 0xe0) | (celsius & 0xf) | ((celsius << 4) & 0x10)
@data[0x04] = c
end
end
end
end
2 changes: 2 additions & 0 deletions lib/device.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
module MideaAirCondition
# Device representation (now only for status parsing)
class Device
attr_reader :data

def initialize(data)
@data = data
@pointer = 0x33
Expand Down
14 changes: 10 additions & 4 deletions lib/midea_air_condition.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
require_relative 'client'
require_relative 'device'
require_relative 'packet_builder'
require_relative 'security'
require_relative 'version'

# MideaAirCondition namespace
module MideaAirCondition
# Module to deparate command classes
module Command
end
end

# path = File.join(File.dirname(__FILE__), 'commands', '*.rb')
# Dir.glob(path).each do |file|
# require file
# end
path = File.join(File.dirname(__FILE__), 'commands', 'command.rb')
require path
path = File.join(File.dirname(__FILE__), 'commands', '*.rb')
Dir.glob(path).each do |file|
require file
end
54 changes: 54 additions & 0 deletions lib/packet_builder.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
module MideaAirCondition
# This is where we build our packets
class PacketBuilder
def initialize(security)
@security = security
@command = []

populate_header_data

# Maybe this one is the client id
# In a response it's the device id
# and the first six bytes are the same
@packet += [0xc6, 0x79, 0x00, 0x00, 0x00, 0x05, 0x0a, 0x00]

add_unknown_section
end

def add_command(command)
raise Exception, 'Invalid argument' if command.is_a?(Command)
@command += command.finalize(@security)
end

def finalize
@packet += @command
@packet << @security.checksum(@command[1..(@command.length - 1)])
@packet << 0x00

# Add padding + update packet length
@packet += [0] * (47 - @command.length)
@packet[0x04] = @packet.length

p @packet

@packet
end

def populate_header_data
# was always fix for me except the length byte
@packet = [0x5a, 0x5a, 0x01, 0x11, 0x5c, 0x00, 0x20, 0x00]
# was different for status and power
# @packet += [0x12, 0x00, 0x00, 0x00, 0x6f, 0x33, 0x0c, 0x00]
@packet += [0x01, 0x00, 0x00, 0x00, 0x8d, 0x0f, 0x17, 0x02]
# was always fix for me
@packet += [0x0e, 0x03, 0x12, 0x14]
end

def add_unknown_section
@packet += [
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00
]
end
end
end
2 changes: 1 addition & 1 deletion lib/security.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def crc8(data)
k = crc_value ^ m
k -= 256 if k > 256
k += 256 if k < 0
crc_value = CRC8_854_TABLE[k]
crc_value = @crc8_854_table[k]
end

crc_value
Expand Down

0 comments on commit f5f991a

Please sign in to comment.