Skip to content

Commit

Permalink
removed dependency on libscrc library. added further enhancements for…
Browse files Browse the repository at this point in the history
… better home assistant integration
  • Loading branch information
samsinnamon committed Nov 24, 2020
1 parent c1a6e28 commit 797b541
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 23 deletions.
15 changes: 15 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python: Current File",
"type": "python",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal"
}
]
}
40 changes: 26 additions & 14 deletions airtouch4pyapi/airtouch.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import socket
import libscrc
from airtouch4pyapi import helper
from airtouch4pyapi import packetmap
from airtouch4pyapi import communicate
Expand Down Expand Up @@ -32,8 +31,8 @@ def __init__(self):
self.GroupNumber = 0
self.IsOn = True
self.OpenPercent = 0
self.CurrentRoomTemp = 0
self.TargetRoomTemp = 0
self.Temperature = 0
self.TargetSetpoint = 0
self.BelongsToAc = -1

class AirTouchAc:
Expand All @@ -44,15 +43,21 @@ def __init__(self):

class AirTouch:
IpAddress = "";
SettingValueTranslator = packetmap.SettingValueTranslator();
def __init__(self, ipAddress):
self.IpAddress = ipAddress;
self.UpdateInfo();

def UpdateInfo(self):
self.acs = dict();
self.groups = dict();
self.IpAddress = ipAddress;

#get the group infos
message = packetmap.MessageFactory.CreateEmptyMessageOfType("GroupStatus");
self.SendMessageToAirtouch(message)

#if the first call gets an error, not worth doing the subsequent ones
if hasattr(self, "error"):
return;
#get the group nicknames
nameMessage = packetmap.MessageFactory.CreateEmptyMessageOfType("GroupName");
self.SendMessageToAirtouch(nameMessage)
Expand Down Expand Up @@ -86,16 +91,13 @@ def SetGroupToTemperatureByGroupName(self, groupName, temperature):
targetGroup = self._getTargetGroup(groupName)
return self.SetGroupToTemperature(targetGroup.GroupNumber, temperature);

#SetCoolingModeByGroup
#SetFanSpeedByGroup
#GetSupportedCoolingModesByGroup
#GetSupportedFanSpeedsByGroup

def SetCoolingModeByGroup(self, groupNumber, coolingMode):
self.SetCoolingModeForAc(self.groups[groupNumber].BelongsToAc, coolingMode);
return self.groups[groupNumber];

def SetFanSpeedByGroup(self, groupNumber, fanSpeed):
self.SetFanSpeedForAc(self.groups[groupNumber].BelongsToAc, fanSpeed);
return self.groups[groupNumber];

def GetSupportedCoolingModesByGroup(self, groupNumber):
return self.GetSupportedCoolingModesForAc(self.groups[groupNumber].BelongsToAc);
Expand All @@ -108,6 +110,7 @@ def TurnGroupOn(self, groupNumber):
controlMessage.SetMessageValue("Power", 3)
controlMessage.SetMessageValue("GroupNumber", groupNumber)
self.SendMessageToAirtouch(controlMessage)
return self.groups[groupNumber];

def TurnAcOn(self, acNumber):
controlMessage = packetmap.MessageFactory.CreateEmptyMessageOfType("AcControl");
Expand Down Expand Up @@ -166,6 +169,7 @@ def TurnGroupOff(self, groupNumber):
controlMessage.SetMessageValue("Power", 2)
controlMessage.SetMessageValue("GroupNumber", groupNumber)
self.SendMessageToAirtouch(controlMessage)
return self.groups[groupNumber];

def SetGroupToTemperature(self, groupNumber, temperature):
controlMessage = packetmap.MessageFactory.CreateEmptyMessageOfType("GroupControl");
Expand All @@ -175,17 +179,21 @@ def SetGroupToTemperature(self, groupNumber, temperature):
controlMessage.SetMessageValue("TargetSetpoint", temperature)
controlMessage.SetMessageValue("GroupNumber", groupNumber)
self.SendMessageToAirtouch(controlMessage)
return self.groups[groupNumber];
#should this turn the group on?

def GetAcs(self):
acs = [AirTouchAc];
acs = [];
for acNumber in self.acs.keys():
ac = self.groups[acNumber]
ac = self.acs[acNumber]
acs.append(ac);
return acs;

def GetGroupByGroupNumber(self, groupNumber):
return self.groups[groupNumber];

def GetGroups(self):
groups = [AirTouchGroup];
groups = [];
for groupNumber in self.groups.keys():
groupInfo = self.groups[groupNumber]
groups.append(groupInfo);
Expand Down Expand Up @@ -213,6 +221,10 @@ def SendMessageToAirtouch(self, messageObject):


def TranslatePacketToMessage(self, dataResult):

if(isinstance(dataResult, Exception)):
self.error = dataResult;
return;
address = dataResult[2:4]
messageId = dataResult[4:5]
messageType = dataResult[5:6]
Expand Down Expand Up @@ -307,4 +319,4 @@ def DecodeAirtouchAcStatusMessage(self, payload):
#set property of entry name on the group response

def _getTargetGroup(self, groupName):
return [group for group in self.groups.values() if group.GroupName == groupName][0]
return [group for group in self.groups.values() if group.GroupName == groupName][0]
39 changes: 32 additions & 7 deletions airtouch4pyapi/communicate.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from airtouch4pyapi import packetmap
import libscrc
import socket
import errno
from socket import error as socket_error

def MessageObjectToMessagePacket(messageObject, mapName):
messageString = "80b001";
Expand Down Expand Up @@ -56,13 +57,37 @@ def TranslateMapValueToValue(groupChunk, map):

def SendMessagePacketToAirtouch(messageString, ipAddress):
#add header, add crc
messageString = "5555" + messageString + format(libscrc.modbus(bytes.fromhex(messageString)), '08x')[4:];
messageString = "5555" + messageString + format(crc16(bytes.fromhex(messageString)), '08x')[4:];

TCP_PORT = 9004
BUFFER_SIZE = 4096
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ipAddress, TCP_PORT))
s.send(bytearray.fromhex(messageString))
data = s.recv(BUFFER_SIZE)
s.close()
return data;
s.settimeout(7)
data = ""
try:
s.connect((ipAddress, TCP_PORT))
s.send(bytearray.fromhex(messageString))
data = s.recv(BUFFER_SIZE)
s.close()
except socket_error as serr:
data = serr;
return data;

import numpy as np

def crc16(data: bytes):
'''
CRC-16-ModBus Algorithm
'''
data = bytearray(data)
poly = 0xA001
crc = 0xFFFF
for b in data:
crc ^= (0xFF & b)
for _ in range(0, 8):
if (crc & 0x0001):
crc = ((crc >> 1) & 0xFFFF) ^ poly
else:
crc = ((crc >> 1) & 0xFFFF)

return np.uint16(crc)
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@

setuptools.setup(
name="airtouch4pyapi", # Replace with your own username
version="0.0.8",
version="0.0.19",
author="Sam Sinnamon",
author_email="[email protected]",
description="An api allowing control of AC state (temperature, on/off, mode) of an Airtouch 4 controller locally over TCP",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/LonePurpleWolf/airtouch4pyapi",
packages=setuptools.find_packages(),
install_requires=['libscrc'],
install_requires=[''],
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
Expand Down

0 comments on commit 797b541

Please sign in to comment.