Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mostly logging updates #30

Merged
merged 12 commits into from
Mar 26, 2023
3 changes: 1 addition & 2 deletions custom_components/intesisbox/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=

async def async_setup_entry(hass, entry, async_add_entities):
controller = hass.data[DOMAIN][entry.entry_id]
controller.poll_status()
async_add_entities([IntesisBoxAC(controller)], True)

class IntesisBoxAC(ClimateEntity):
Expand Down Expand Up @@ -250,7 +249,7 @@ def set_swing_mode(self, swing_mode):
async def async_update(self):
"""Copy values from controller dictionary to climate device."""
if not self._controller.is_connected:
await asyncio.sleep(1) # per device specs, wait min 1 sec before re-connecting
await asyncio.sleep(60) # per device specs, wait min 1 sec before re-connecting
await self.hass.async_add_executor_job(self._controller.connect)
self._connection_retries += 1
else:
Expand Down
86 changes: 60 additions & 26 deletions custom_components/intesisbox/intesisbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from asyncio import ensure_future
from time import sleep

_LOGGER = logging.getLogger('pyintesisbox')
_LOGGER = logging.getLogger(__name__)

API_DISCONNECTED = "Disconnected"
API_CONNECTING = "Connecting"
Expand All @@ -35,7 +35,7 @@
FUNCTION_ERRSTATUS = 'ERRSTATUS'
FUNCTION_ERRCODE = 'ERRCODE'

NULL_VALUE = '32768'
NULL_VALUE = '-32768'


class IntesisBox(asyncio.Protocol):
Expand Down Expand Up @@ -74,30 +74,35 @@ async def keep_alive(self):
"""Send a keepalive command to reset it's watchdog timer."""
while self.is_connected:
_LOGGER.debug("Sending keepalive")
self._transport.write("PING\r".encode('ascii'))
self._write("PING")
await asyncio.sleep(45)
else:
_LOGGER.debug("Not connected, skipping keepalive")

async def query_initial_state(self):
self._transport.write("ID\r".encode('ascii'))
await asyncio.sleep(1)
self._transport.write("LIMITS:SETPTEMP\r".encode('ascii'))
await asyncio.sleep(1)
self._transport.write("LIMITS:FANSP\r".encode('ascii'))
await asyncio.sleep(1)
self._transport.write("LIMITS:MODE\r".encode('ascii'))
await asyncio.sleep(1)
self._transport.write("LIMITS:VANEUD\r".encode('ascii'))
await asyncio.sleep(1)
self._transport.write("LIMITS:VANELR\r".encode('ascii'))
cmds = [
"ID",
"LIMITS:SETPTEMP",
"LIMITS:FANSP",
"LIMITS:MODE",
"LIMITS:VANEUD",
"LIMITS:VANELR",
]
for cmd in cmds:
self._write(cmd)
await asyncio.sleep(1)

def _write(self, cmd):
self._transport.write(f"{cmd}\r".encode('ascii'))
_LOGGER.debug(f"Data sent: {cmd!r}")

def data_received(self, data):
"""asyncio callback when data is received on the socket"""
decoded_data = data.decode('ascii')
_LOGGER.debug("Data received: {}".format(decoded_data))
linesReceived = decoded_data.splitlines()
linesReceived = data.decode('ascii').splitlines()
statusChanged = False

for line in linesReceived:
_LOGGER.debug(f"Data received: {line!r}")
cmdList = line.split(':', 1)
cmd = cmdList[0]
args = None
Expand All @@ -107,12 +112,16 @@ def data_received(self, data):
self._parse_id_received(args)
self._connectionStatus = API_AUTHENTICATED
asyncio.ensure_future(self.keep_alive())
asyncio.ensure_future(self.poll_status())
elif cmd == 'CHN,1':
self._parse_change_received(args)
statusChanged = True
elif cmd == 'LIMITS':
self._parse_limits_received(args)
statusChanged = True

self._send_update_callback()
if statusChanged:
self._send_update_callback()

def _parse_id_received(self, args):
# ID:Model,MAC,IP,Protocol,Version,RSSI
Expand All @@ -123,13 +132,24 @@ def _parse_id_received(self, args):
self._firmversion = info[4]
self._rssi = info[5]

_LOGGER.debug(
"Updated info:",
f"model:{self._model}",
f"mac:{self._mac}",
f"version:{self._firmversion}",
f"rssi:{self._rssi}",
)


def _parse_change_received(self, args):
function = args.split(',')[0]
value = args.split(',')[1]
if value == NULL_VALUE:
value = None
self._device[function] = value

_LOGGER.debug(f"Updated state: {self._device!r}")

def _parse_limits_received(self, args):
split_args = args.split(',', 1)

Expand All @@ -148,6 +168,16 @@ def _parse_limits_received(self, args):
self._vertical_vane_list = values
elif function == FUNCTION_VANELR:
self._horizontal_vane_list = values

_LOGGER.debug(
"Updated limits: ",
f"{self._setpoint_minimum=}",
f"{self._setpoint_maximum=}",
f"{self._fan_speed_list=}",
f"{self._operation_list=}",
f"{self._vertical_vane_list=}",
f"{self._horizontal_vane_list=}",
)
return

def connection_lost(self, exc):
Expand All @@ -172,18 +202,27 @@ def connect(self):
ensure_future(coro, loop=self._eventLoop)
else:
_LOGGER.debug("Missing IP address or port.")
self._connectionStatus = API_DISCONNECTED

except Exception as e:
_LOGGER.error('%s Exception. %s / %s', type(e), repr(e.args), e)
self._connectionStatus = API_DISCONNECTED
else:
_LOGGER.debug('connect() called but already connecting')

def stop(self):
"""Public method for shutting down connectivity with the envisalink."""
self._connectionStatus = API_DISCONNECTED
self._transport.close()

def poll_status(self, sendcallback=False):
self._transport.write("GET,1:*\r".encode('ascii'))
async def poll_status(self, sendcallback=False):
"""Periodically poll for updates since the controllers don't always update reliably"""
while self.is_connected:
_LOGGER.debug("Polling for update")
self._write("GET,1:*")
await asyncio.sleep(60*5) # 5 minutes
else:
_LOGGER.debug("Not connected, skipping poll_status()")

def set_temperature(self, setpoint):
"""Public method for setting the temperature"""
Expand All @@ -204,10 +243,8 @@ def set_horizontal_vane(self, vane: str):

def _set_value(self, uid, value):
"""Internal method to send a command to the API"""
message = "SET,{}:{},{}\r".format(1, uid, value)
try:
self._transport.write(message.encode('ascii'))
_LOGGER.debug("Data sent: {!r}".format(message))
self._write(f"SET,1:{uid},{value}")
except Exception as e:
_LOGGER.error('%s Exception. %s / %s', type(e), e.args, e)

Expand Down Expand Up @@ -292,9 +329,6 @@ def ambient_temperature(self) -> float:
temperature = self._device.get(FUNCTION_AMBTEMP)
if temperature:
temperature = int(temperature) / 10
# When unsupported, -32768 is reported
if temperature == -3276.8:
temperature = None
return temperature

@property
Expand Down