Skip to content

Commit

Permalink
Fix deprecated supported features and more
Browse files Browse the repository at this point in the history
- Fix deprecated supported features and constants
- Updated socket management to properly handle entities that may become unavailable
- Updated the strings.json file and corresponding translations
- Deleted the SpaGateway entity because I now manage entity availability better
  • Loading branch information
plmilord authored Feb 5, 2024
1 parent ba9d4f1 commit 054822e
Show file tree
Hide file tree
Showing 10 changed files with 65 additions and 96 deletions.
2 changes: 1 addition & 1 deletion custom_components/spaclient/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ async def async_setup_entry(hass, config_entry):
hass.data[DOMAIN][config_entry.entry_id] = {SPA: spa, DATA_LISTENER: [config_entry.add_update_listener(update_listener)]}

connected = await spa.validate_connection()

if not connected:
_LOGGER.error("Failed to connect to spa at %s", config_entry.data[CONF_HOST])
raise ConfigEntryNotReady

await spa.send_module_identification_request()
Expand Down
41 changes: 2 additions & 39 deletions custom_components/spaclient/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
# Import the device class from the component that you want to support
from . import SpaClientDevice
from .const import _LOGGER, DOMAIN, ICONS, SPA
from homeassistant.components.binary_sensor import BinarySensorEntity, DEVICE_CLASS_CONNECTIVITY

from datetime import timedelta
from homeassistant.components.binary_sensor import BinarySensorEntity

SCAN_INTERVAL = timedelta(seconds=1)


Expand All @@ -22,8 +22,6 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
for i in range(0, 2):
entities.append(FilterCycle(i + 1, spaclient, config_entry))

entities.append(SpaGateway(spaclient, config_entry))

async_add_entities(entities, True)


Expand Down Expand Up @@ -117,38 +115,3 @@ def is_on(self):
def available(self) -> bool:
"""Return True if entity is available."""
return self._spaclient.get_gateway_status()


class SpaGateway(SpaClientDevice, BinarySensorEntity):
"""Representation of a binary sensor."""

def __init__(self, spaclient, config_entry):
"""Initialize the device."""
super().__init__(spaclient, config_entry)
self._spaclient = spaclient
self._sensor_type = DEVICE_CLASS_CONNECTIVITY

@property
def unique_id(self) -> str:
"""Return a unique ID."""
return f"{self._spaclient.get_macaddr().replace(':', '')}#bwa_wi_fi_module"

@property
def device_class(self):
"""Return the class of this binary sensor."""
return self._sensor_type

@property
def name(self):
"""Return the name of the binary sensor."""
return 'bwa Wi-Fi Module'

@property
def is_on(self):
"""Return the state of the binary sensor."""
return self._spaclient.get_gateway_status()

@property
def available(self) -> bool:
"""Return True if entity is available."""
return self._spaclient.get_gateway_status()
18 changes: 8 additions & 10 deletions custom_components/spaclient/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,14 @@
# Import the device class from the component that you want to support
from . import SpaClientDevice
from .const import _LOGGER, DOMAIN, ICONS, SPA
from homeassistant.components.climate import ClimateEntity
from homeassistant.components.climate.const import SUPPORT_TARGET_TEMPERATURE, HVAC_MODE_HEAT, HVAC_MODE_OFF
from datetime import timedelta
from homeassistant.components.climate import ClimateEntity, ClimateEntityFeature, HVACMode
from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature
from homeassistant.util.unit_conversion import TemperatureConverter

from datetime import timedelta
SCAN_INTERVAL = timedelta(seconds=1)

SUPPORT_HVAC = [HVAC_MODE_HEAT, HVAC_MODE_OFF]
SUPPORT_FLAGS = (SUPPORT_TARGET_TEMPERATURE)
SUPPORT_HVAC = [HVACMode.HEAT, HVACMode.OFF]


async def async_setup_entry(hass, config_entry, async_add_entities):
Expand Down Expand Up @@ -53,8 +51,8 @@ def icon(self):
def hvac_mode(self):
"""Return current HVAC mode."""
if self._spaclient.get_heating():
return HVAC_MODE_HEAT
return HVAC_MODE_OFF
return HVACMode.HEAT
return HVACMode.OFF

@property
def hvac_modes(self):
Expand All @@ -64,7 +62,7 @@ def hvac_modes(self):
@property
def supported_features(self):
"""Return the list of supported features."""
return SUPPORT_FLAGS
return ClimateEntityFeature.TARGET_TEMPERATURE

@property
def current_temperature(self):
Expand Down Expand Up @@ -99,8 +97,8 @@ async def async_set_temperature(self, **kwargs):
async def async_set_hvac_mode(self, hvac_mode):
"""Set new target HVAC mode."""
if self._spaclient.get_heating():
return HVAC_MODE_HEAT
return HVAC_MODE_OFF
return HVACMode.HEAT
return HVACMode.OFF

@property
def min_temp(self):
Expand Down
2 changes: 1 addition & 1 deletion custom_components/spaclient/light.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
# Import the device class from the component that you want to support
from . import SpaClientDevice
from .const import _LOGGER, DOMAIN, SPA
from datetime import timedelta
from homeassistant.components.light import LightEntity

from datetime import timedelta
SCAN_INTERVAL = timedelta(seconds=1)


Expand Down
2 changes: 1 addition & 1 deletion custom_components/spaclient/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
"documentation": "https://github.com/plmilord/Hass.io-custom-component-spaclient",
"iot_class": "local_push",
"issue_tracker": "https://github.com/plmilord/Hass.io-custom-component-spaclient/issues",
"version": "2.8"
"version": "2.81"
}
80 changes: 44 additions & 36 deletions custom_components/spaclient/spaclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def __init__(self, host_ip):
self.hour = 0
self.minute = 0
self.heat_mode = "Rest"
self.temp_scale = "Farenheit"
self.temp_scale = "Fahrenheit"
self.filter_mode = False
self.time_scale = "24 Hr"
self.heating = False
Expand Down Expand Up @@ -93,35 +93,35 @@ def __init__(self, host_ip):
self.nb_of_pumps = 0
self.additional_information_loaded = False

def get_socket(self):
if self.s is None or self.is_connected == False:
async def get_socket(self):
if self.s is None:
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.s.setblocking(0)
self.s.settimeout(5)

try:
self.s.connect((self.host_ip, 4257))
except socket.error as e:
#_LOGGER.info("socket.error = %s", e) #Validation point
if e.errno != 115:
self.s.close()
self.is_connected = False
return True

return True
return True
except (socket.timeout, socket.error) as e:
#_LOGGER.error("Socket connection error: %s", e) #Validation point
self.is_connected = False
self.s.close()
self.s = None
return True

async def validate_connection(self):
count = 0

self.get_socket()
await self.get_socket()

while count != 20 and self.is_connected != True:
self.read_msg()
await asyncio.sleep(.1)
count += 1
if self.s is not None:
while count < 20 or self.is_connected == False:
self.read_msg()
await asyncio.sleep(.1)
count += 1

if self.is_connected == False:
self.s.close()
self.s = None
if self.is_connected == False:
self.s.close()
self.s = None

return self.is_connected

Expand Down Expand Up @@ -640,32 +640,32 @@ def read_msg(self):

try:
len_chunk = self.s.recv(2)
except IOError as e:
#_LOGGER.info("1. read_msg - e.errno = %s", e) #Validation point
if e.errno != 11:
self.get_socket()
except (socket.timeout, socket.error) as e:
#_LOGGER.error("self.s.recv(2) error = %s", e) #Validation point
self.is_connected = False
self.l.release()
self.s.close()
self.s = None
return True

if len_chunk == b'~' or len_chunk == b'' or len(len_chunk) == 0:
#_LOGGER.info("2. read_msg - len_chunk = %s ; len(len_chunk) = %s", len_chunk, len(len_chunk)) #Validation point
self.l.release()
return True

length = len_chunk[1]

if int(length) == 0:
#_LOGGER.info("3. read_msg - int(length) = 0") #Validation point
self.l.release()
return True

try:
chunk = self.s.recv(length)
except IOError as e:
#_LOGGER.info("4. read_msg - e.errno = %s", e) #Validation point
if e.errno != 11:
self.get_socket()
except (socket.timeout, socket.error) as e:
#_LOGGER.error("self.s.recv(length) error = %s", e) #Validation point
self.is_connected = False
self.l.release()
self.s.close()
self.s = None
return True

self.l.release()
Expand Down Expand Up @@ -722,7 +722,8 @@ def read_msg(self):

async def read_all_msg(self):
while True:
self.read_msg()
if self.s is not None:
self.read_msg()
await asyncio.sleep(.1)

def send_message(self, type, payload):
Expand All @@ -734,10 +735,14 @@ def send_message(self, type, payload):
try:
#_LOGGER.info("send_message : %s", message) #Validation point
self.s.send(message)
except IOError as e:
#_LOGGER.info("send_message - IOError = %s", e) #Validation point
if e.errno != 11:
self.get_socket()
return True
except (socket.timeout, socket.error) as e:
#_LOGGER.error("self.s.send(message) error = %s", e) #Validation point
self.is_connected = False
self.l.release()
self.s.close()
self.s = None
return True

async def send_module_identification_request(self):
self.send_message(b'\x0a\xbf\x04', bytes([]))
Expand All @@ -746,7 +751,10 @@ async def send_module_identification_request(self):

async def keep_alive_call(self):
while True:
self.send_message(b'\x0a\xbf\x04', bytes([]))
if self.s is None:
await self.get_socket()
else:
self.send_message(b'\x0a\xbf\x04', bytes())
await asyncio.sleep(30)

def send_toggle_message(self, item):
Expand Down
6 changes: 3 additions & 3 deletions custom_components/spaclient/strings.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
{
"config": {
"abort": {
"already_configured": "Device is already configured"
"already_configured": "This bwa Wi-Fi Module is already configured"
},
"error": {
"cannot_connect": "Failed to connect, please try again",
"cannot_connect": "Unable to connect to this bwa Wi-Fi Module, please try again",
"unknown": "Unexpected error"
},
"step": {
"user": {
"data": {
"host": "Host",
"host": "Host name or IP address",
"name": "Name"
}
}
Expand Down
2 changes: 1 addition & 1 deletion custom_components/spaclient/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
# Import the device class from the component that you want to support
from . import SpaClientDevice
from .const import _LOGGER, DOMAIN, ICONS, SPA
from datetime import timedelta
from homeassistant.components.switch import SwitchEntity

from datetime import timedelta
SCAN_INTERVAL = timedelta(seconds=1)


Expand Down
2 changes: 1 addition & 1 deletion custom_components/spaclient/time.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
# Import the device class from the component that you want to support
from . import SpaClientDevice
from .const import _LOGGER, DOMAIN, FILTER_CYCLE_TIMES, SPA
from datetime import time, timedelta
from homeassistant.components.time import TimeEntity

from datetime import time, timedelta
SCAN_INTERVAL = timedelta(seconds=1)


Expand Down
6 changes: 3 additions & 3 deletions custom_components/spaclient/translations/en.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
{
"config": {
"abort": {
"already_configured": "Device is already configured"
"already_configured": "This bwa Wi-Fi Module is already configured"
},
"error": {
"cannot_connect": "Failed to connect, please try again",
"cannot_connect": "Unable to connect to this bwa Wi-Fi Module, please try again",
"unknown": "Unexpected error"
},
"step": {
"user": {
"data": {
"host": "Host",
"host": "Host name or IP address",
"name": "Name"
}
}
Expand Down

0 comments on commit 054822e

Please sign in to comment.