Skip to content

Commit

Permalink
First stage of v5 support
Browse files Browse the repository at this point in the history
  • Loading branch information
Cemil Browne committed Nov 27, 2022
1 parent 16bba50 commit 7d5b5c6
Show file tree
Hide file tree
Showing 10 changed files with 53 additions and 17 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"python.pythonPath": "/usr/local/bin/python3"
}
2 changes: 1 addition & 1 deletion airtouch4pyapi/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from airtouch4pyapi.airtouch import AirTouch, AirTouchStatus
from airtouch4pyapi.airtouch import AirTouch, AirTouchStatus, AirTouchVersion
Binary file added airtouch4pyapi/__pycache__/__init__.cpython-39.pyc
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added airtouch4pyapi/__pycache__/helper.cpython-39.pyc
Binary file not shown.
Binary file not shown.
35 changes: 26 additions & 9 deletions airtouch4pyapi/airtouch.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from airtouch4pyapi import packetmap
from airtouch4pyapi import communicate
from enum import Enum

#API

# class Airtouch
Expand Down Expand Up @@ -34,6 +35,9 @@ class AirTouchStatus(Enum):
CONNECTION_LOST = 3,
ERROR = 4

class AirTouchVersion(Enum):
AIRTOUCH4 = 4,
AIRTOUCH5 = 5

class AirTouchGroup:
def __init__(self):
Expand All @@ -59,32 +63,36 @@ def __init__(self):
class AirTouch:
IpAddress = "";
SettingValueTranslator = packetmap.SettingValueTranslator();
def __init__(self, ipAddress):
def __init__(self, ipAddress, atVersion = AirTouchVersion.AIRTOUCH4):
self.IpAddress = ipAddress;
self.Status = AirTouchStatus.NOT_CONNECTED;
self.Messages = dict();

self.atVersion = atVersion;

async def UpdateInfo(self):
self.acs = dict();
self.groups = dict();
self.Messages:List[AirTouchError] = [];
#get the group infos
message = packetmap.MessageFactory.CreateEmptyMessageOfType("GroupStatus");
message = packetmap.MessageFactory.CreateEmptyMessageOfType("GroupStatus", self.atVersion);
await self.SendMessageToAirtouch(message)
### test
return


#if the first call means we still have an error status, not worth doing the subsequent ones
if(self.Status != AirTouchStatus.OK):
return;
#get the group nicknames
nameMessage = packetmap.MessageFactory.CreateEmptyMessageOfType("GroupName");
nameMessage = packetmap.MessageFactory.CreateEmptyMessageOfType("GroupName", self.atVersion);
await self.SendMessageToAirtouch(nameMessage)

#get ac infos
acsMessage = packetmap.MessageFactory.CreateEmptyMessageOfType("AcStatus");
acsMessage = packetmap.MessageFactory.CreateEmptyMessageOfType("AcStatus", self.atVersion);
await self.SendMessageToAirtouch(acsMessage)

#allocate acs to groups (ac ability?)
acAbilityMessage = packetmap.MessageFactory.CreateEmptyMessageOfType("AcAbility");
acAbilityMessage = packetmap.MessageFactory.CreateEmptyMessageOfType("AcAbility", self.atVersion);
await self.SendMessageToAirtouch(acAbilityMessage)

for group in self.groups.values():
Expand Down Expand Up @@ -234,21 +242,30 @@ def GetGroups(self):
async def SendMessageToAirtouch(self, messageObject):
if(messageObject.MessageType == "GroupStatus"):
MESSAGE = "80b0012b0000"
if(messageObject.MessageType == "GroupStatus5"):
MESSAGE = "80b001c000082100000000000000"

if(messageObject.MessageType == "GroupName"):

MESSAGE = "90b0011f0002ff12"
if(messageObject.MessageType == "GroupName5"):
MESSAGE = ""

if(messageObject.MessageType == "AcAbility"):
MESSAGE = "90b0011f0002ff11"
if(messageObject.MessageType == "AcAbility5"):
MESSAGE = ""

if(messageObject.MessageType == "AcStatus"):
if(messageObject.MessageType == "AcStatus"):
MESSAGE = "80b0012d0000f4cf"
if(messageObject.MessageType == "AcStatus5"):
MESSAGE = ""

if(messageObject.MessageType == "GroupControl" or messageObject.MessageType == "AcControl"):
MESSAGE = communicate.MessageObjectToMessagePacket(messageObject, messageObject.MessageType);

try:
dataResult = await communicate.SendMessagePacketToAirtouch(MESSAGE, self.IpAddress)
dataResult = await communicate.SendMessagePacketToAirtouch(MESSAGE, self.IpAddress, self.atVersion)
self.Status = AirTouchStatus.OK
except Exception as e:
if(self.Status == AirTouchStatus.OK):
Expand All @@ -273,7 +290,7 @@ def TranslatePacketToMessage(self, dataResult):
messageType = dataResult[5:6]
dataLength = dataResult[6:8]

if(messageType == b'\x2b'):
if(messageType == b'\xc0'):
self.DecodeAirtouchGroupStatusMessage(dataResult[8::]);
if(messageType == b'\x1f'):
self.DecodeAirtouchExtendedMessage(dataResult[8::]);
Expand Down
15 changes: 9 additions & 6 deletions airtouch4pyapi/communicate.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import asyncio
import errno
from socket import error as socket_error
#### CEMIL TEST
from hexdump import hexdump

def MessageObjectToMessagePacket(messageObject, mapName):
messageString = "80b001";
Expand Down Expand Up @@ -56,18 +58,19 @@ def TranslateMapValueToValue(groupChunk, map):
return byteSegmentAsValue

#might raise a socket or os error if connection fails
async def SendMessagePacketToAirtouch(messageString, ipAddress):
async def SendMessagePacketToAirtouch(messageString, ipAddress, atVersion):
#add header, add crc
messageString = "5555" + messageString + format(crc16(bytes.fromhex(messageString)), '08x')[4:]

TCP_PORT = 9004
messageString = "555555aa" + messageString + format(crc16(bytes.fromhex(messageString)), '08x')[4:]
if(atVersion.value == 5):
TCP_PORT = 9005
else:
TCP_PORT = 9004
BUFFER_SIZE = 4096
reader, writer = await asyncio.open_connection(ipAddress, TCP_PORT)

writer.write(bytearray.fromhex(messageString))
response = await asyncio.wait_for(reader.read(BUFFER_SIZE), timeout=2.0)

writer.close()
print(hexdump(response))
await writer.wait_closed()

return response;
Expand Down
15 changes: 14 additions & 1 deletion airtouch4pyapi/packetmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,17 @@ class DataLocationTranslator:
"Temperature" : "5:6-16",
"Spill": "6:5-5"
},
"GroupStatus5" : {
"PowerState" : "1:7-8",
"GroupNumber" : "1:1-6",
"ControlMethod" : "2:8-8",
"OpenPercentage" : "2:1-7",
"BatteryLow" : "7:1-1",
"TargetSetpoint" : "3:1-8",
"Sensor" : "4:8-8",
"Temperature" : "5:1-16",
"Spill": "7:2-2"
},
"AcStatus" : {
"PowerState" : "1:7-8",
"AcNumber" : "1:1-6",
Expand Down Expand Up @@ -141,7 +152,9 @@ def SetMessageValue(self, propertyName, newValue):

class MessageFactory:
@staticmethod
def CreateEmptyMessageOfType(messageType):
def CreateEmptyMessageOfType(messageType, atVersion):
if(atVersion.value == 5):
messageType = messageType + "5"
message = Message(messageType);
for attr in DataLocationTranslator.map[messageType]:
message.MessageValues[attr] = 0;
Expand Down

0 comments on commit 7d5b5c6

Please sign in to comment.