Skip to content

Commit

Permalink
Add Number, Time, Input entity component (#164)
Browse files Browse the repository at this point in the history
* Implementation of Time, Number input entity and maintenance of Select entity

* Add as_zero value to number setting

* Correction of Number and maintenance of ENL_OP_CODES

* Comment out of develop test part

* lint fix

* Simplify using features included in pychonet

* Adjusting automatic configuration of input entities

* Bugfix

* Automatically assigning icons using device_class and optimizing import syntax

And enbug fixes.

* Comment out develop test part
  • Loading branch information
nao-pon authored Feb 3, 2024
1 parent 0ac9284 commit 623e597
Show file tree
Hide file tree
Showing 13 changed files with 958 additions and 387 deletions.
67 changes: 61 additions & 6 deletions custom_components/echonetlite/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""The echonetlite integration."""

from __future__ import annotations
import logging
import pychonet as echonet
Expand All @@ -11,13 +12,23 @@
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.util import Throttle
from homeassistant.const import Platform
from homeassistant.const import (
Platform,
PERCENTAGE,
UnitOfPower,
UnitOfTemperature,
UnitOfEnergy,
UnitOfVolume,
UnitOfElectricCurrent,
UnitOfElectricPotential,
)
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.components.sensor import SensorDeviceClass
from homeassistant.components.number import NumberDeviceClass
from .const import (
DOMAIN,
USER_OPTIONS,
TEMP_OPTIONS,
CONF_FORCE_POLLING,
CONF_BATCH_SIZE_MAX,
MISC_OPTIONS,
)
Expand Down Expand Up @@ -46,8 +57,6 @@
ENL_HVAC_ROOM_TEMP,
ENL_HVAC_SILENT_MODE,
ENL_HVAC_OUT_TEMP,
ENL_HVAC_HUMIDIFIER_STATE,
ENL_HVAC_HUMIDIFIER_VALUE,
)

from pychonet.DistributionPanelMeter import (
Expand All @@ -64,7 +73,6 @@

from pychonet.LowVoltageSmartElectricEnergyMeter import (
ENL_LVSEEM_COEF,
ENL_LVSEEM_DIGITS,
ENL_LVSEEM_ENG_UNIT,
ENL_LVSEEM_ENG_NOR,
ENL_LVSEEM_ENG_REV,
Expand All @@ -84,6 +92,8 @@
Platform.LIGHT,
Platform.FAN,
Platform.SWITCH,
Platform.TIME,
Platform.NUMBER,
]
PARALLEL_UPDATES = 0
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=1)
Expand Down Expand Up @@ -187,6 +197,52 @@ def polling_update_debug_log(values, eojgc, eojcc):
return debug_log


def get_unit_by_devise_class(device_class: str) -> str | None:
if (
device_class == SensorDeviceClass.TEMPERATURE
or device_class == NumberDeviceClass.TEMPERATURE
):
unit = UnitOfTemperature.CELSIUS
elif (
device_class == SensorDeviceClass.ENERGY
or device_class == NumberDeviceClass.ENERGY
):
unit = UnitOfEnergy.WATT_HOUR
elif (
device_class == SensorDeviceClass.POWER
or device_class == NumberDeviceClass.POWER
):
unit = UnitOfPower.WATT
elif (
device_class == SensorDeviceClass.CURRENT
or device_class == NumberDeviceClass.CURRENT
):
unit = UnitOfElectricCurrent.AMPERE
elif (
device_class == SensorDeviceClass.VOLTAGE
or device_class == NumberDeviceClass.VOLTAGE
):
unit = UnitOfElectricPotential.VOLT
elif (
device_class == SensorDeviceClass.HUMIDITY
or device_class == SensorDeviceClass.BATTERY
or device_class == NumberDeviceClass.HUMIDITY
or device_class == NumberDeviceClass.BATTERY
):
unit = PERCENTAGE
elif device_class == SensorDeviceClass.GAS or device_class == NumberDeviceClass.GAS:
unit = UnitOfVolume.CUBIC_METERS
elif (
device_class == SensorDeviceClass.WATER
or device_class == NumberDeviceClass.WATER
):
unit = UnitOfVolume.CUBIC_METERS
else:
unit = None

return unit


async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
entry.async_on_unload(entry.add_update_listener(update_listener))
host = None
Expand Down Expand Up @@ -406,7 +462,6 @@ class ECHONETConnector:
def __init__(self, instance, hass, entry):
self.hass = hass
self._host = instance["host"]
self._instance = None
self._eojgc = instance["eojgc"]
self._eojcc = instance["eojcc"]
self._eojci = instance["eojci"]
Expand Down
79 changes: 39 additions & 40 deletions custom_components/echonetlite/climate.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import logging

from pychonet.HomeAirConditioner import (
AIRFLOW_VERT,
ENL_STATUS,
ENL_FANSPEED,
ENL_AIR_VERT,
Expand All @@ -11,6 +12,8 @@
ENL_HVAC_SET_HUMIDITY,
ENL_HVAC_ROOM_TEMP,
ENL_HVAC_SILENT_MODE,
FAN_SPEED,
SILENT_MODE,
)

from pychonet.EchonetInstance import ENL_GETMAP
Expand All @@ -32,34 +35,22 @@
from homeassistant.const import (
ATTR_TEMPERATURE,
PRECISION_WHOLE,
UnitOfTemperature,
)
from .const import DOMAIN, SILENT_MODE_OPTIONS, OPTION_HA_UI_SWING
from .const import DATA_STATE_ON, DOMAIN, OPTION_HA_UI_SWING

_LOGGER = logging.getLogger(__name__)

SUPPORT_FLAGS = 0

DEFAULT_FAN_MODES = [
"auto",
"minimum",
"low",
"medium-low",
"medium",
"medium-high",
"high",
"very-high",
"max",
]
DEFAULT_FAN_MODES = list(
FAN_SPEED.keys()
) # ["auto","minimum","low","medium-low","medium","medium-high","high","very-high","max"]
DEFAULT_HVAC_MODES = ["heat", "cool", "dry", "fan_only", "heat_cool", "off"]
DEFAULT_SWING_MODES = [
"auto-vert",
"upper",
"upper-central",
"central",
"lower-central",
"lower",
]
DEFAULT_PRESET_MODES = ["normal", "high-speed", "silent"]
DEFAULT_SWING_MODES = ["auto-vert"] + list(
AIRFLOW_VERT.keys()
) # ["auto-vert","upper","upper-central","central","lower-central","lower"]
DEFAULT_PRESET_MODES = list(SILENT_MODE.keys()) # ["normal", "high-speed", "silent"]

SERVICE_SET_HUMIDIFER_DURING_HEATER = "set_humidifier_during_heater"
ATTR_STATE = "state"
Expand All @@ -73,11 +64,7 @@ async def async_setup_entry(hass, config_entry, async_add_devices):
if (
entity["instance"]["eojgc"] == 0x01 and entity["instance"]["eojcc"] == 0x30
): # Home Air Conditioner
entities.append(
EchonetClimate(
config_entry.title, entity["echonetlite"], hass.config.units
)
)
entities.append(EchonetClimate(config_entry.title, entity["echonetlite"]))
async_add_devices(entities, True)

platform = entity_platform.async_get_current_platform()
Expand All @@ -98,7 +85,12 @@ class EchonetClimate(ClimateEntity):
_attr_translation_key = DOMAIN

def __init__(
self, name, connector, units: UnitSystem, fan_modes=None, swing_vert=None
self,
name,
connector,
units: UnitSystem | None = None,
fan_modes=None,
swing_vert=None,
):
"""Initialize the climate device."""
self._name = name
Expand All @@ -107,7 +99,10 @@ def __init__(
self._uid = (
self._connector._uidi if self._connector._uidi else self._connector._uid
)
self._unit_of_measurement = units.temperature_unit
# The temperature unit of echonet lite is defined as Celsius.
# Set temperature_unit setting to Celsius,
# HA's automatic temperature unit conversion function works correctly.
self._unit_of_measurement = UnitOfTemperature.CELSIUS
self._precision = 1.0
self._target_temperature_step = 1
self._support_flags = SUPPORT_FLAGS
Expand All @@ -117,6 +112,14 @@ def __init__(
self._server_state = self._connector._api._state[
self._connector._instance._host
]
self._opc_data = {
ENL_AUTO_DIRECTION: list(
self._connector._instance.EPC_FUNCTIONS[ENL_AUTO_DIRECTION][1].values()
),
ENL_SWING_MODE: list(
self._connector._instance.EPC_FUNCTIONS[ENL_SWING_MODE][1].values()
),
}
if ENL_FANSPEED in list(self._connector._setPropertyMap):
self._support_flags = self._support_flags | ClimateEntityFeature.FAN_MODE
if ENL_AIR_VERT in list(self._connector._setPropertyMap):
Expand Down Expand Up @@ -168,7 +171,7 @@ def device_info(self):
"manufacturer": self._connector._manufacturer,
"model": EOJX_CLASS[self._connector._instance._eojgc][
self._connector._instance._eojcc
]
],
# "sw_version": "",
}

Expand Down Expand Up @@ -237,7 +240,7 @@ def available(self) -> bool:
def hvac_mode(self):
"""Return current operation ie. heat, cool, idle."""
mode = self._connector._update_data[ENL_HVAC_MODE]
if self._connector._update_data[ENL_STATUS] == "On":
if self._connector._update_data[ENL_STATUS] == DATA_STATE_ON:
if mode == "auto":
mode = HVACMode.HEAT_COOL
elif mode == "other":
Expand All @@ -254,7 +257,7 @@ def hvac_mode(self):
@property
def hvac_action(self):
"""Return current operation ie. heat, cool, idle."""
if self._connector._update_data[ENL_STATUS] == "On":
if self._connector._update_data[ENL_STATUS] == DATA_STATE_ON:
if self._connector._update_data[ENL_HVAC_MODE] == HVACMode.HEAT:
return HVACAction.HEATING
elif self._connector._update_data[ENL_HVAC_MODE] == HVACMode.COOL:
Expand Down Expand Up @@ -300,7 +303,9 @@ def hvac_modes(self):
@property
def is_on(self):
"""Return true if the device is on."""
return True if self._connector._update_data[ENL_STATUS] == "On" else False
return (
True if self._connector._update_data[ENL_STATUS] == DATA_STATE_ON else False
)

@property
def fan_mode(self):
Expand Down Expand Up @@ -369,15 +374,9 @@ def swing_mode(self):

async def async_set_swing_mode(self, swing_mode):
"""Set new swing mode."""
if (
self._connector._user_options.get(ENL_AUTO_DIRECTION)
and swing_mode in self._connector._user_options[ENL_AUTO_DIRECTION]
):
if swing_mode in self._opc_data[ENL_AUTO_DIRECTION]:
await self._connector._instance.setAutoDirection(swing_mode)
elif (
self._connector._user_options.get(ENL_SWING_MODE)
and swing_mode in self._connector._user_options[ENL_SWING_MODE]
):
elif swing_mode in self._opc_data[ENL_SWING_MODE]:
await self._connector._instance.setSwingMode(swing_mode)
else:
await self._connector._instance.setAirflowVert(swing_mode)
Expand Down
12 changes: 9 additions & 3 deletions custom_components/echonetlite/config_flow.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Config flow for echonetlite integration."""

from __future__ import annotations

import logging
Expand Down Expand Up @@ -189,6 +190,7 @@ async def enumerate_instances(
uidi = f"{uid}-{eojgc}-{eojcc}-{instance}"
name = None
if host_product_code == "WTY2001" and eojcc == 0x91:
# Panasonic WTY2001 Advanced Series Link Plus Wireless Adapter
await server.echonetMessage(
host,
eojgc,
Expand All @@ -197,9 +199,11 @@ async def enumerate_instances(
GET,
[{"EPC": 0xFD}, {"EPC": 0xFE}],
)
uidi = _null_padded_optional_string(
state["instances"][eojgc][eojcc][instance][0xFE]
)
# When updating the previous environment, the entity ID will change if the uidi changes, so this should be postponed.
# Reconsider if the instance number changes dynamically.
# uidi = _null_padded_optional_string(
# state["instances"][eojgc][eojcc][instance][0xFE]
# )
name = _null_padded_optional_string(
state["instances"][eojgc][eojcc][instance][0xFD]
)
Expand Down Expand Up @@ -289,6 +293,8 @@ async def async_step_user(
if len(_detected_hosts):
host = list(_detected_hosts.keys()).pop(0)
title = _detected_hosts[host][0]["manufacturer"]
if _detected_hosts[host][0]["host_product_code"]:
title += " " + _detected_hosts[host][0]["host_product_code"]
else:
if user_input is None:
host = title = WORD_OF_AUTO_DISCOVERY
Expand Down
Loading

0 comments on commit 623e597

Please sign in to comment.