Skip to content

Commit

Permalink
Code optimization
Browse files Browse the repository at this point in the history
  • Loading branch information
Limych committed May 1, 2020
1 parent 0a43e8c commit 1ad2bd3
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 127 deletions.
104 changes: 84 additions & 20 deletions custom_components/jq300/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,21 @@
import homeassistant.util.dt as dt_util
import requests
import voluptuous as vol
from homeassistant.components.sensor import DOMAIN as SENSOR
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR
from homeassistant.components.sensor import DOMAIN as SENSOR
from homeassistant.const import CONF_USERNAME, CONF_PASSWORD, CONF_DEVICES, \
CONF_DEVICE_ID, CONCENTRATION_PARTS_PER_BILLION, \
CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER, CONCENTRATION_PARTS_PER_MILLION
from homeassistant.helpers import discovery
from requests import PreparedRequest

from .const import DOMAIN, VERSION, ISSUE_URL, SUPPORT_LIB_URL, DATA_JQ300, \
QUERY_TYPE_API, QUERY_TYPE_DEVICE, QUERY_METHOD_GET, BASE_URL_API, \
BASE_URL_DEVICE, USERAGENT_API, USERAGENT_DEVICE, QUERY_TIMEOUT, \
MSG_GENERIC_FAIL, MSG_LOGIN_FAIL, QUERY_METHOD_POST, MSG_BUSY, \
SENSORS, UPDATE_MIN_TIME, CONF_RECEIVE_TVOC_IN_PPB, \
CONF_RECEIVE_HCHO_IN_PPB, SENSORS_FILTER_TIME, MWEIGTH_TVOC, MWEIGTH_HCHO, \
ATTR_DEVICE_BRAND, ATTR_DEVICE_MODEL, ATTR_DEVICE_ID, ATTR_RAW_STATE, \
BINARY_SENSORS
QUERY_TYPE_API, QUERY_TYPE_DEVICE, BASE_URL_API, BASE_URL_DEVICE, \
USERAGENT_API, USERAGENT_DEVICE, QUERY_TIMEOUT, MSG_GENERIC_FAIL, \
MSG_LOGIN_FAIL, MSG_BUSY, SENSORS, UPDATE_MIN_TIME, \
CONF_RECEIVE_TVOC_IN_PPB, CONF_RECEIVE_HCHO_IN_PPB, SENSORS_FILTER_TIME, \
MWEIGTH_TVOC, MWEIGTH_HCHO, ATTR_DEVICE_BRAND, ATTR_DEVICE_MODEL, \
ATTR_DEVICE_ID, ATTR_RAW_STATE, BINARY_SENSORS

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -66,25 +65,24 @@ async def async_setup(hass, config):

controller = JqController(
username, password, receive_tvoc_in_ppb, receive_hcho_in_ppb)
hass.data[DATA_JQ300][username] = controller
_LOGGER.info('Connected to cloud account %s', username)

devs = controller.get_devices_list()
if not devs:
_LOGGER.error("Can't receive devices list from cloud.")
return False
for dev_id in devs.keys():
for dev_id in devs:
if devices and devs[dev_id]['pt_name'] not in devices:
continue
device = JqDevice(controller, dev_id)
hass.data[DATA_JQ300][device.unique_id] = device
hass.async_create_task(
discovery.async_load_platform(hass, BINARY_SENSOR, DOMAIN, {
CONF_USERNAME: username,
CONF_DEVICE_ID: dev_id,
CONF_DEVICE_ID: device.unique_id,
}, config))
hass.async_create_task(
discovery.async_load_platform(hass, SENSOR, DOMAIN, {
CONF_USERNAME: username,
CONF_DEVICE_ID: dev_id,
CONF_DEVICE_ID: device.unique_id,
}, config))

return True
Expand All @@ -97,7 +95,7 @@ class JqController:
# pylint: disable=R0913
def __init__(self, username, password, receive_tvoc_in_ppb=False,
receive_hcho_in_ppb=False):
"""Initialize configured device."""
"""Initialize configured controller."""
self.params = {
'uid': -1000,
'safeToken': 'anonymous',
Expand Down Expand Up @@ -125,13 +123,13 @@ def __init__(self, username, password, receive_tvoc_in_ppb=False,
self._units[sensor_id] = data[1]

@property
def unique_id(self):
"""Return a device unique ID."""
def unique_id(self) -> str:
"""Return a controller unique ID."""
return self._username

@property
def name(self):
"""Get custom device name."""
def name(self) -> str:
"""Get custom controller name."""
return 'JQ300'

@property
Expand All @@ -140,7 +138,7 @@ def available(self) -> bool:
return self._login()

@property
def units(self):
def units(self) -> dict:
"""Get list of units for sensors."""
return self._units

Expand Down Expand Up @@ -392,3 +390,69 @@ def get_sensors(self, device_id) -> Optional[dict]:
def get_sensors_raw(self, device_id) -> Optional[dict]:
"""Get raw values of states of available sensors for device."""
return self._sensors_raw.get(device_id)


class JqDevice:
"""JQ device controller"""

def __init__(self, controller: JqController, device_id):
"""Initialize configured device."""
self._controller = controller
self._device_id = device_id

device = controller.get_devices_list()
# _LOGGER.debug(device)
if not device:
_LOGGER.error("Can't receive devices list from cloud.")
return
self._device = device[device_id]

self._unique_id = '{}-{}'.format(
self._controller.unique_id, self._device_id)
self._available = False

@property
def unique_id(self) -> str:
"""Return a device unique ID."""
return self._unique_id

@property
def name(self) -> str:
"""Get custom device name."""
return self._device['pt_name']

@property
def available(self) -> bool:
"""Return True if device is available."""
return self._controller.available
# pylint: disable=W0511
# todo: Add check for device availability

@property
def units(self) -> dict:
"""Get list of units for sensors."""
return self._controller.units

@property
def sensors(self) -> Optional[dict]:
"""Get states of available sensors for device."""
return self._controller.get_sensors(self._device_id)

@property
def sensors_raw(self) -> Optional[dict]:
"""Get raw values of states of available sensors for device."""
return self._controller.get_sensors_raw(self._device_id)

@property
def device_state_attributes(self):
"""Return the device state attributes."""
return {
ATTR_DEVICE_BRAND: self._device['brandname'],
ATTR_DEVICE_MODEL: self._device['pt_model'],
ATTR_DEVICE_ID: self._device['deviceid'],
}

@property
def should_poll(self) -> bool:
"""Return the polling state."""
return True
74 changes: 23 additions & 51 deletions custom_components/jq300/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,11 @@

from homeassistant.components.binary_sensor import BinarySensorDevice, \
ENTITY_ID_FORMAT
from homeassistant.const import (
CONF_USERNAME,
CONF_DEVICE_ID)
from homeassistant.const import CONF_DEVICE_ID
from homeassistant.helpers.entity import async_generate_entity_id

from . import DATA_JQ300
from .const import BINARY_SENSORS, ATTR_DEVICE_BRAND, ATTR_DEVICE_MODEL, \
ATTR_DEVICE_ID
from . import JqDevice
from .const import DATA_JQ300, BINARY_SENSORS

_LOGGER = logging.getLogger(__name__)

Expand All @@ -33,62 +30,46 @@ async def async_setup_platform(hass, config, async_add_entities,
if discovery_info is None:
return

account_id = discovery_info[CONF_USERNAME]
device_id = discovery_info[CONF_DEVICE_ID]
_LOGGER.debug('Setup binary sensors for device %s', device_id)
device_uid = discovery_info[CONF_DEVICE_ID]
_LOGGER.debug('Setup binary sensors for device %s', device_uid)

controller = hass.data[DATA_JQ300][account_id] # type: JqController
device = controller.get_devices_list()
device = hass.data[DATA_JQ300][device_uid] # type: JqDevice
dev_sensors = device.sensors
# _LOGGER.debug(device)
if not device:
_LOGGER.error("Can't receive devices list from cloud.")
return
device = device[device_id]
dev_name = device['pt_name']
sensors_data = controller.get_sensors(device_id)
# _LOGGER.debug(sensors_data)
if not sensors_data:
if not dev_sensors:
_LOGGER.error("Can't receive sensors list for device '%s' from cloud.",
device['pt_name'])
device_uid)
return

sensor_id = 1
ent_name = BINARY_SENSORS.get(sensor_id)[4] \
or BINARY_SENSORS.get(sensor_id)[0]
entity_id = async_generate_entity_id(
ENTITY_ID_FORMAT, f"{dev_name}_{ent_name}", hass=hass)
_LOGGER.debug("Initialize %s for account %s", entity_id, account_id)
ENTITY_ID_FORMAT, f"{device.name}_{ent_name}", hass=hass)
_LOGGER.debug("Initialize %s", entity_id)
async_add_entities([JqBinarySensor(
hass, controller, device, sensor_id, sensors_data[sensor_id],
entity_id)])
entity_id, device, sensor_id, dev_sensors[sensor_id])])


# pylint: disable=R0902
class JqBinarySensor(BinarySensorDevice):
"""A binary sensor implementation for JQ device"""

# pylint: disable=R0913,W0613
def __init__(self, hass, controller, device, sensor_id, sensor_state,
entity_id):
"""Initialize a sensor"""
def __init__(self, entity_id, device: JqDevice, sensor_id, sensor_state):
"""Initialize a binary sensor"""
super().__init__()

self._controller = controller # type: JqController
self._device_id = device['deviceid']
self._device_brand = device['brandname']
self._device_model = device['pt_model']
self.entity_id = entity_id

self._device = device
self._sensor_id = sensor_id
self._unique_id = '{}-{}'.format(device.unique_id, sensor_id)
self._name = "{0} {1}".format(
device['pt_name'], BINARY_SENSORS.get(sensor_id)[0])
device.name, BINARY_SENSORS.get(sensor_id)[0])
self._state = sensor_state
self._units = controller.units[sensor_id]
self._icon = BINARY_SENSORS.get(sensor_id)[2]
self._unique_id = '{}-{}-{}'.format(
self._controller.unique_id, self._device_id, sensor_id)
self._device_class = BINARY_SENSORS.get(sensor_id)[3]

self.entity_id = entity_id

@property
def name(self):
"""Return the name of the binary sensor."""
Expand All @@ -97,7 +78,7 @@ def name(self):
@property
def available(self) -> bool:
"""Return True if entity is available."""
return self._controller.available
return self._device.available

@property
def is_on(self):
Expand All @@ -117,31 +98,22 @@ def device_class(self):
@property
def device_state_attributes(self):
"""Return the state attributes."""
attrs = {
ATTR_DEVICE_BRAND: self._device_brand,
ATTR_DEVICE_MODEL: self._device_model,
ATTR_DEVICE_ID: self._device_id,
}
attrs = self._device.device_state_attributes
return attrs

@property
def icon(self):
"""Icon to use in the frontend, if any."""
return self._icon

@property
def unit_of_measurement(self):
"""Return the units of measurement."""
return self._units

@property
def should_poll(self):
"""Return the polling state."""
return True
return self._device.should_poll

def update(self):
"""Update the sensor state if it needed."""
ret = self._controller.get_sensors_raw(self._device_id)
ret = self._device.sensors_raw
if ret:
self._state = ret[self._sensor_id]
_LOGGER.debug('Update state: %s = %s', self.entity_id, self._state)
11 changes: 4 additions & 7 deletions custom_components/jq300/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

# Base component constants
DOMAIN = "jq300"
VERSION = "0.7.5"
VERSION = "0.7.6"
ISSUE_URL = "https://github.com/Limych/ha-jq300/issues"
ATTRIBUTION = None
DATA_JQ300 = 'jq300'
Expand All @@ -36,9 +36,6 @@
QUERY_TYPE_API = 'API'
QUERY_TYPE_DEVICE = 'DEVICE'

QUERY_METHOD_GET = 'GET'
QUERY_METHOD_POST = 'POST'

BASE_URL_API = "http://www.youpinyuntai.com:32086/ypyt-api/api/app/"
BASE_URL_DEVICE = "https://www.youpinyuntai.com:31447/device/"

Expand Down Expand Up @@ -111,7 +108,7 @@
ATTR_RAW_STATE = 'raw_state'

UPDATE_MIN_TIME = 20 # seconds
SENSORS_FILTER_TIME = 600 # seconds
SENSORS_FILTER_TIME = 900 # seconds

MWEIGTH_TVOC = 56.1060 # g/mol
MWEIGTH_HCHO = 30.0260 # g/mol
MWEIGTH_TVOC = 56.1060 # g/mol
MWEIGTH_HCHO = 30.0260 # g/mol
Loading

0 comments on commit 1ad2bd3

Please sign in to comment.