diff --git a/custom_components/switchbotremote/button.py b/custom_components/switchbotremote/button.py index 2e34ef9..1d6f7b7 100644 --- a/custom_components/switchbotremote/button.py +++ b/custom_components/switchbotremote/button.py @@ -6,7 +6,19 @@ from homeassistant.helpers.entity import DeviceInfo from .client.remote import SupportedRemote -from .const import DOMAIN, IR_CAMERA_TYPES, IR_FAN_TYPES, IR_LIGHT_TYPES, CLASS_BY_TYPE +from .const import ( + DOMAIN, + IR_CAMERA_TYPES, + IR_FAN_TYPES, + IR_LIGHT_TYPES, + CLASS_BY_TYPE, + CONF_CUSTOMIZE_COMMANDS, + CONF_WITH_ION, + CONF_WITH_TIMER, + CONF_WITH_BRIGHTNESS, + CONF_WITH_TEMPERATURE, +) + class SwitchBotRemoteButton(ButtonEntity): _attr_has_entity_name = False @@ -58,7 +70,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry, async_add_e for remote in remotes: options = entry.data.get(remote.id, {}) - customize_commands = options.get("customize_commands", "") + customize_commands = options.get(CONF_CUSTOMIZE_COMMANDS, []) if (remote.type in IR_CAMERA_TYPES): entities.append(SwitchBotRemoteButton( @@ -69,21 +81,21 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry, async_add_e hass, remote, "TIMER", "mdi:timer")) if (remote.type in IR_FAN_TYPES): - if (options.get("with_ion", False)): + if (options.get(CONF_WITH_ION, False)): entities.append(SwitchBotRemoteButton( hass, remote, "ION", "mdi:air-filter")) - if (options.get("with_timer", False)): + if (options.get(CONF_WITH_TIMER, False)): entities.append(SwitchBotRemoteButton( hass, remote, "TIMER", "mdi:timer")) if (remote.type in IR_LIGHT_TYPES): - if (options.get("with_brightness", False)): + if (options.get(CONF_WITH_BRIGHTNESS, False)): entities.append(SwitchBotRemoteButton( hass, remote, "DARKER", "mdi:brightness-4")) entities.append(SwitchBotRemoteButton( hass, remote, "BRIGHTER", "mdi:brightness-6")) - if (options.get("with_temperature", False)): + if (options.get(CONF_WITH_TEMPERATURE, False)): entities.append(SwitchBotRemoteButton( hass, remote, "WARM", "mdi:octagram-minus")) entities.append(SwitchBotRemoteButton( diff --git a/custom_components/switchbotremote/climate.py b/custom_components/switchbotremote/climate.py index d9d1fc0..574d633 100644 --- a/custom_components/switchbotremote/climate.py +++ b/custom_components/switchbotremote/climate.py @@ -16,7 +16,19 @@ from homeassistant.config_entries import ConfigEntry from .client.remote import SupportedRemote -from .const import (DOMAIN, IR_CLIMATE_TYPES, AIR_CONDITIONER_CLASS) +from .const import ( + DOMAIN, + IR_CLIMATE_TYPES, + AIR_CONDITIONER_CLASS, + CONF_POWER_SENSOR, + CONF_TEMPERATURE_SENSOR, + CONF_HUMIDITY_SENSOR, + CONF_TEMP_MIN, + CONF_TEMP_MAX, + CONF_TEMP_STEP, + CONF_HVAC_MODES, +) +from .config_flow import DEFAULT_HVAC_MODES _LOGGER = logging.getLogger(__name__) @@ -42,6 +54,7 @@ class SwitchBotRemoteClimate(ClimateEntity, RestoreEntity): _attr_has_entity_name = False + _attr_force_update = True def __init__(self, sb: SupportedRemote, options: dict = {}) -> None: super().__init__() @@ -52,22 +65,20 @@ def __init__(self, sb: SupportedRemote, options: dict = {}) -> None: self.options = options self._last_on_operation = None - self._operation_modes = [ - HVACMode.OFF, - HVACMode.COOL, - HVACMode.DRY, - HVACMode.FAN_ONLY, - HVACMode.HEAT, - ] + self._operation_modes = options.get( + CONF_HVAC_MODES, DEFAULT_HVAC_MODES) + + if HVACMode.OFF not in self._operation_modes: + self._operation_modes.append(HVACMode.OFF) self._hvac_mode = HVACMode.OFF self._temperature_unit = TEMP_CELSIUS self._target_temperature = 28 - self._target_temperature_step = options.get("temp_step", 1) - self._max_temp = options.get("temp_max", DEFAULT_MAX_TEMP) - self._min_temp = options.get("temp_min", DEFAULT_MIN_TEMP) - self._power_sensor = options.get("power_sensor", None) + self._target_temperature_step = options.get(CONF_TEMP_STEP, 1) + self._max_temp = options.get(CONF_TEMP_MAX, DEFAULT_MAX_TEMP) + self._min_temp = options.get(CONF_TEMP_MIN, DEFAULT_MIN_TEMP) + self._power_sensor = options.get(CONF_POWER_SENSOR, None) self._fan_mode = FAN_AUTO self._fan_modes = [ @@ -79,8 +90,8 @@ def __init__(self, sb: SupportedRemote, options: dict = {}) -> None: self._supported_features = ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.FAN_MODE - self._temperature_sensor = options.get("temperature_sensor", None) - self._humidity_sensor = options.get("humidity_sensor", None) + self._temperature_sensor = options.get(CONF_TEMPERATURE_SENSOR, None) + self._humidity_sensor = options.get(CONF_HUMIDITY_SENSOR, None) self._current_temperature = None self._current_humidity = None @@ -288,21 +299,24 @@ async def async_added_to_hass(self): 'last_on_operation') if self._temperature_sensor: - async_track_state_change(self.hass, self._temperature_sensor, self._async_temp_sensor_changed) + async_track_state_change( + self.hass, self._temperature_sensor, self._async_temp_sensor_changed) temp_sensor_state = self.hass.states.get(self._temperature_sensor) if temp_sensor_state and temp_sensor_state.state != STATE_UNKNOWN: self._async_update_temp(temp_sensor_state) if self._humidity_sensor: - async_track_state_change(self.hass, self._humidity_sensor, self._async_humidity_sensor_changed) + async_track_state_change( + self.hass, self._humidity_sensor, self._async_humidity_sensor_changed) humidity_sensor_state = self.hass.states.get(self._humidity_sensor) if humidity_sensor_state and humidity_sensor_state.state != STATE_UNKNOWN: self._async_update_humidity(humidity_sensor_state) if self._power_sensor: - async_track_state_change(self.hass, self._power_sensor, self._async_power_sensor_changed) + async_track_state_change( + self.hass, self._power_sensor, self._async_power_sensor_changed) power_sensor_state = self.hass.states.get(self._power_sensor) if power_sensor_state and power_sensor_state.state != STATE_UNKNOWN: diff --git a/custom_components/switchbotremote/config_flow.py b/custom_components/switchbotremote/config_flow.py index efd06d7..ba00cc4 100644 --- a/custom_components/switchbotremote/config_flow.py +++ b/custom_components/switchbotremote/config_flow.py @@ -11,6 +11,7 @@ from homeassistant.data_entry_flow import FlowResult from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers.selector import selector +from homeassistant.components.climate.const import HVACMode from .client import SwitchBot from .const import ( @@ -25,8 +26,42 @@ VACUUM_CLASS, WATER_HEATER_CLASS, OTHERS_CLASS, + + CONF_POWER_SENSOR, + CONF_TEMPERATURE_SENSOR, + CONF_HUMIDITY_SENSOR, + CONF_TEMP_MIN, + CONF_TEMP_MAX, + CONF_TEMP_STEP, + CONF_HVAC_MODES, + CONF_CUSTOMIZE_COMMANDS, + CONF_WITH_SPEED, + CONF_WITH_ION, + CONF_WITH_TIMER, + CONF_WITH_BRIGHTNESS, + CONF_WITH_TEMPERATURE, + CONF_ON_COMMAND, + CONF_OFF_COMMAND, ) +DEFAULT_HVAC_MODES = [ + HVACMode.AUTO, + HVACMode.COOL, + HVACMode.DRY, + HVACMode.FAN_ONLY, + HVACMode.HEAT, + HVACMode.OFF, +] + +HVAC_MODES = [ + {"label": "Auto", "value": str(HVACMode.AUTO)}, + {"label": "Cool", "value": str(HVACMode.COOL)}, + {"label": "Dry", "value": str(HVACMode.DRY)}, + {"label": "Fan Only", "value": str(HVACMode.FAN_ONLY)}, + {"label": "Heat", "value": str(HVACMode.HEAT)}, + {"label": "Off", "value": str(HVACMode.OFF)}, +] + _LOGGER = logging.getLogger(__name__) STEP_USER_DATA_SCHEMA = vol.Schema( @@ -37,60 +72,52 @@ } ) -# TODO: Fix the entity selector default value or empty issue STEP_CONFIGURE_DEVICE = { AIR_CONDITIONER_CLASS: lambda x: vol.Schema({ - # selector({"entity": {"filter": {"domain": ["binary_sensor","input_boolean","light","sensor","switch"]}}}) - vol.Optional("power_sensor", default=x.get("power_sensor", "")): str, - # selector({"entity": {"filter": {"domain": "sensor"}}}) - vol.Optional("temperature_sensor", default=x.get("temperature_sensor", "")): str, - # selector({"entity": {"filter": {"domain": "sensor"}}}) - vol.Optional("humidity_sensor", default=x.get("humidity_sensor", "")): str, - vol.Optional("temp_min", default=x.get("temp_min", 16)): int, - vol.Optional("temp_max", default=x.get("temp_max", 30)): int, - vol.Optional("temp_step", default=x.get("temp_step", 1.0)): selector({"number": {"min": 0.1, "max": 2.0, "step": 0.1, "mode": "slider"}}), - vol.Optional("customize_commands", default=x.get("customize_commands", [])): selector({"select": {"multiple": True, "custom_value": True, "options": []}}), + vol.Optional(CONF_POWER_SENSOR, description={"suggested_value": x.get(CONF_POWER_SENSOR)}): selector({"entity": {"filter": {"domain": ["binary_sensor", "input_boolean", "light", "sensor", "switch"]}}}), + vol.Optional(CONF_TEMPERATURE_SENSOR, description={"suggested_value": x.get(CONF_TEMPERATURE_SENSOR)}): selector({"entity": {"filter": {"domain": "sensor"}}}), + vol.Optional(CONF_HUMIDITY_SENSOR, description={"suggested_value": x.get(CONF_HUMIDITY_SENSOR)}): selector({"entity": {"filter": {"domain": "sensor"}}}), + vol.Optional(CONF_TEMP_MIN, default=x.get(CONF_TEMP_MIN, 16)): int, + vol.Optional(CONF_TEMP_MAX, default=x.get(CONF_TEMP_MAX, 30)): int, + vol.Optional(CONF_TEMP_STEP, default=x.get(CONF_TEMP_STEP, 1.0)): selector({"number": {"min": 0.1, "max": 2.0, "step": 0.1, "mode": "slider"}}), + vol.Optional(CONF_HVAC_MODES, description={"suggested_value": x.get(CONF_HVAC_MODES, DEFAULT_HVAC_MODES)}): vol.All(selector({"select": {"multiple": True, "options": HVAC_MODES}})), + vol.Optional(CONF_CUSTOMIZE_COMMANDS, default=x.get(CONF_CUSTOMIZE_COMMANDS, [])): selector({"select": {"multiple": True, "custom_value": True, "options": []}}), }), MEDIA_CLASS: lambda x: vol.Schema({ - # selector({"entity": {"filter": {"domain": ["binary_sensor","input_boolean","light","sensor","switch"]}}}) - vol.Optional("power_sensor", default=x.get("power_sensor", "")): str, - vol.Optional("customize_commands", default=x.get("customize_commands", [])): selector({"select": {"multiple": True, "custom_value": True, "options": []}}), + vol.Optional(CONF_POWER_SENSOR, description={"suggested_value": x.get(CONF_POWER_SENSOR)}): selector({"entity": {"filter": {"domain": ["binary_sensor", "input_boolean", "light", "sensor", "switch"]}}}), + vol.Optional(CONF_CUSTOMIZE_COMMANDS, default=x.get(CONF_CUSTOMIZE_COMMANDS, [])): selector({"select": {"multiple": True, "custom_value": True, "options": []}}), }), FAN_CLASS: lambda x: vol.Schema({ - # selector({"entity": {"filter": {"domain": ["binary_sensor","input_boolean","light","sensor","switch"]}}}) - vol.Optional("power_sensor", default=x.get("power_sensor", "")): str, - vol.Optional("with_speed", default=x.get("with_speed", False)): bool, - vol.Optional("with_ion", default=x.get("with_ion", False)): bool, - vol.Optional("with_timer", default=x.get("with_timer", False)): bool, - vol.Optional("customize_commands", default=x.get("customize_commands", [])): selector({"select": {"multiple": True, "custom_value": True, "options": []}}), + vol.Optional(CONF_POWER_SENSOR, description={"suggested_value": x.get(CONF_POWER_SENSOR)}): selector({"entity": {"filter": {"domain": ["binary_sensor", "input_boolean", "light", "sensor", "switch"]}}}), + vol.Optional(CONF_WITH_SPEED, default=x.get(CONF_WITH_SPEED, False)): bool, + vol.Optional(CONF_WITH_ION, default=x.get(CONF_WITH_ION, False)): bool, + vol.Optional(CONF_WITH_TIMER, default=x.get(CONF_WITH_TIMER, False)): bool, + vol.Optional(CONF_CUSTOMIZE_COMMANDS, default=x.get(CONF_CUSTOMIZE_COMMANDS, [])): selector({"select": {"multiple": True, "custom_value": True, "options": []}}), }), LIGHT_CLASS: lambda x: vol.Schema({ - # selector({"entity": {"filter": {"domain": ["binary_sensor","input_boolean","light","sensor","switch"]}}}) - vol.Optional("power_sensor", default=x.get("power_sensor", "")): str, - vol.Optional("with_brightness", default=x.get("with_brightness", False)): bool, - vol.Optional("with_temperature", default=x.get("with_temperature", False)): bool, - vol.Optional("customize_commands", default=x.get("customize_commands", [])): selector({"select": {"multiple": True, "custom_value": True, "options": []}}), + vol.Optional(CONF_POWER_SENSOR, description={"suggested_value": x.get(CONF_POWER_SENSOR)}): selector({"entity": {"filter": {"domain": ["binary_sensor", "input_boolean", "light", "sensor", "switch"]}}}), + vol.Optional(CONF_WITH_BRIGHTNESS, default=x.get(CONF_WITH_BRIGHTNESS, False)): bool, + vol.Optional(CONF_WITH_TEMPERATURE, default=x.get(CONF_WITH_TEMPERATURE, False)): bool, + vol.Optional(CONF_CUSTOMIZE_COMMANDS, default=x.get(CONF_CUSTOMIZE_COMMANDS, [])): selector({"select": {"multiple": True, "custom_value": True, "options": []}}), }), CAMERA_CLASS: lambda x: vol.Schema({ - vol.Optional("customize_commands", default=x.get("customize_commands", [])): selector({"select": {"multiple": True, "custom_value": True, "options": []}}), + vol.Optional(CONF_CUSTOMIZE_COMMANDS, default=x.get(CONF_CUSTOMIZE_COMMANDS, [])): selector({"select": {"multiple": True, "custom_value": True, "options": []}}), }), VACUUM_CLASS: lambda x: vol.Schema({ - vol.Optional("customize_commands", default=x.get("customize_commands", [])): selector({"select": {"multiple": True, "custom_value": True, "options": []}}), + vol.Optional(CONF_CUSTOMIZE_COMMANDS, default=x.get(CONF_CUSTOMIZE_COMMANDS, [])): selector({"select": {"multiple": True, "custom_value": True, "options": []}}), }), WATER_HEATER_CLASS: lambda x: vol.Schema({ - # selector({"entity": {"filter": {"domain": ["binary_sensor","input_boolean","light","sensor","switch"]}}}) - vol.Optional("power_sensor", default=x.get("power_sensor", "")): str, - vol.Optional("temperature_sensor", default=x.get("temperature_sensor", "")): selector({"entity": {"filter": {"domain": "sensor"}}}), - vol.Optional("temp_min", default=x.get("temp_min", 40)): int, - vol.Optional("temp_max", default=x.get("temp_max", 65)): int, - vol.Optional("customize_commands", default=x.get("customize_commands", [])): selector({"select": {"multiple": True, "custom_value": True, "options": []}}), + vol.Optional(CONF_POWER_SENSOR, description={"suggested_value": x.get(CONF_POWER_SENSOR)}): selector({"entity": {"filter": {"domain": ["binary_sensor", "input_boolean", "light", "sensor", "switch"]}}}), + vol.Optional(CONF_TEMPERATURE_SENSOR, description={"suggested_value": x.get(CONF_TEMPERATURE_SENSOR)}): selector({"entity": {"filter": {"domain": "sensor"}}}), + vol.Optional(CONF_TEMP_MIN, default=x.get(CONF_TEMP_MIN, 40)): int, + vol.Optional(CONF_TEMP_MAX, default=x.get(CONF_TEMP_MAX, 65)): int, + vol.Optional(CONF_CUSTOMIZE_COMMANDS, default=x.get(CONF_CUSTOMIZE_COMMANDS, [])): selector({"select": {"multiple": True, "custom_value": True, "options": []}}), }), OTHERS_CLASS: lambda x: vol.Schema({ - # selector({"entity": {"filter": {"domain": ["binary_sensor","input_boolean","light","sensor","switch"]}}}) - vol.Optional("power_sensor", default=x.get("power_sensor", "")): str, - vol.Optional("on_command", default=x.get("on_command", "")): str, - vol.Optional("off_command", default=x.get("off_command", "")): str, - vol.Optional("customize_commands", default=x.get("customize_commands", [])): selector({"select": {"multiple": True, "custom_value": True, "options": []}}), + vol.Optional(CONF_POWER_SENSOR, description={"suggested_value": x.get(CONF_POWER_SENSOR)}): selector({"entity": {"filter": {"domain": ["binary_sensor", "input_boolean", "light", "sensor", "switch"]}}}), + vol.Optional(CONF_ON_COMMAND, default=x.get(CONF_ON_COMMAND, "")): str, + vol.Optional(CONF_OFF_COMMAND, default=x.get(CONF_OFF_COMMAND, "")): str, + vol.Optional(CONF_CUSTOMIZE_COMMANDS, default=x.get(CONF_CUSTOMIZE_COMMANDS, [])): selector({"select": {"multiple": True, "custom_value": True, "options": []}}), }), } @@ -168,10 +195,7 @@ async def async_step_init(self, user_input: dict[str, Any] | None = None) -> Flo for remote in self.discovered_devices: devices[remote.id] = remote.name - return self.async_show_form( - step_id="init", - data_schema=vol.Schema({vol.Required("selected_device"): vol.In(devices)}) - ) + return self.async_show_form(step_id="init", data_schema=vol.Schema({vol.Required("selected_device"): vol.In(devices)})) async def async_step_edit_device(self, user_input=None): """Handle editing a device.""" @@ -187,9 +211,9 @@ async def async_step_edit_device(self, user_input=None): schema = vol.Schema({}) for remote in self.discovered_devices: if remote.id == self.selected_device and remote.type in CLASS_BY_TYPE: + config = self.config_entry.data.get(remote.id, {}) schema = STEP_CONFIGURE_DEVICE[CLASS_BY_TYPE[remote.type]]( - self.config_entry.data.get(remote.id, {}) - ) + config) return self.async_show_form( step_id="edit_device", diff --git a/custom_components/switchbotremote/const.py b/custom_components/switchbotremote/const.py index ec4ddc1..12dc041 100644 --- a/custom_components/switchbotremote/const.py +++ b/custom_components/switchbotremote/const.py @@ -3,6 +3,22 @@ DOMAIN = "switchbotremote" +CONF_POWER_SENSOR = "power_sensor" +CONF_TEMPERATURE_SENSOR = "temperature_sensor" +CONF_HUMIDITY_SENSOR = "humidity_sensor" +CONF_TEMP_MIN = "temp_min" +CONF_TEMP_MAX = "temp_max" +CONF_TEMP_STEP = "temp_step" +CONF_HVAC_MODES = "hvac_modes" +CONF_CUSTOMIZE_COMMANDS = "customize_commands" +CONF_WITH_SPEED = "with_speed" +CONF_WITH_ION = "with_ion" +CONF_WITH_TIMER = "with_timer" +CONF_WITH_BRIGHTNESS = "with_brightness" +CONF_WITH_TEMPERATURE = "with_temperature" +CONF_ON_COMMAND = "on_command" +CONF_OFF_COMMAND = "off_command" + """Supported Devices""" DIY_AIR_CONDITIONER_TYPE = "DIY Air Conditioner" AIR_CONDITIONER_TYPE = "Air Conditioner" diff --git a/custom_components/switchbotremote/fan.py b/custom_components/switchbotremote/fan.py index 6d67325..fadad90 100644 --- a/custom_components/switchbotremote/fan.py +++ b/custom_components/switchbotremote/fan.py @@ -12,8 +12,7 @@ from homeassistant.helpers.event import async_track_state_change from .client.remote import SupportedRemote -from .const import (DOMAIN, IR_FAN_TYPES, FAN_CLASS, - AIR_PURIFIER_TYPE, DIY_AIR_PURIFIER_TYPE) +from .const import DOMAIN, IR_FAN_TYPES, FAN_CLASS, AIR_PURIFIER_TYPE, DIY_AIR_PURIFIER_TYPE, CONF_WITH_SPEED, CONF_POWER_SENSOR _LOGGER = logging.getLogger(__name__) @@ -51,9 +50,9 @@ def __init__(self, hass: HomeAssistant, sb: SupportedRemote, options: dict = {}) self._speed = AIR_PURIFIER_SPEED_COMMANDS[0] if sb.type in IR_AIR_PURIFIER_TYPES else SPEED_COMMANDS[0] self._supported_features = 0 - self._power_sensor = options.get("power_sensor", None) + self._power_sensor = options.get(CONF_POWER_SENSOR, None) - if options.get("with_speed", None): + if options.get(CONF_WITH_SPEED, None): self._supported_features = FanEntityFeature.SET_SPEED if sb.type not in IR_AIR_PURIFIER_TYPES: @@ -111,7 +110,8 @@ async def async_added_to_hass(self): async def async_set_percentage(self, percentage: int) -> None: """Set the speed of the fan, as a percentage.""" - speed = percentage_to_ordered_list_item(AIR_PURIFIER_SPEED_COMMANDS if self.sb.type in IR_AIR_PURIFIER_TYPES else SPEED_COMMANDS, percentage) + speed = percentage_to_ordered_list_item( + AIR_PURIFIER_SPEED_COMMANDS if self.sb.type in IR_AIR_PURIFIER_TYPES else SPEED_COMMANDS, percentage) await self.send_command(speed) self._speed = speed @@ -158,7 +158,8 @@ async def async_added_to_hass(self): await super().async_added_to_hass() if self._power_sensor: - async_track_state_change(self.hass, self._power_sensor, self._async_power_sensor_changed) + async_track_state_change( + self.hass, self._power_sensor, self._async_power_sensor_changed) power_sensor_state = self.hass.states.get(self._power_sensor) if power_sensor_state and power_sensor_state.state != STATE_UNKNOWN: diff --git a/custom_components/switchbotremote/light.py b/custom_components/switchbotremote/light.py index 7500875..af21752 100644 --- a/custom_components/switchbotremote/light.py +++ b/custom_components/switchbotremote/light.py @@ -9,10 +9,11 @@ from homeassistant.const import STATE_UNAVAILABLE, STATE_UNKNOWN, STATE_OFF, STATE_ON from .client.remote import SupportedRemote -from .const import (DOMAIN, IR_LIGHT_TYPES, LIGHT_CLASS) +from .const import DOMAIN, IR_LIGHT_TYPES, LIGHT_CLASS, CONF_POWER_SENSOR _LOGGER = logging.getLogger(__name__) + class SwitchBotRemoteLight(LightEntity, RestoreEntity): _attr_has_entity_name = False @@ -25,7 +26,7 @@ def __init__(self, hass: HomeAssistant, sb: SupportedRemote, options: dict = {}) self._state = STATE_OFF self._brightness = None - self._power_sensor = options.get("power_sensor", None) + self._power_sensor = options.get(CONF_POWER_SENSOR, None) async def send_command(self, *args): await self._hass.async_add_executor_job(self.sb.command, *args) @@ -111,7 +112,8 @@ async def async_added_to_hass(self): await super().async_added_to_hass() if self._power_sensor: - async_track_state_change(self.hass, self._power_sensor, self._async_power_sensor_changed) + async_track_state_change( + self.hass, self._power_sensor, self._async_power_sensor_changed) power_sensor_state = self.hass.states.get(self._power_sensor) if power_sensor_state and power_sensor_state.state != STATE_UNKNOWN: diff --git a/custom_components/switchbotremote/manifest.json b/custom_components/switchbotremote/manifest.json index 8155cb0..6582151 100644 --- a/custom_components/switchbotremote/manifest.json +++ b/custom_components/switchbotremote/manifest.json @@ -5,12 +5,14 @@ "@KiraPC", "@joshepw" ], - "config_flow": true, "dependencies": [], - "documentation": "https://www.home-assistant.io/integrations/switchbotremote", + "integration_type": "hub", + "config_flow": true, + "documentation": "https://github.com/KiraPC/ha-switchbot-remote#readme", + "issue_tracker": "https://github.com/KiraPC/ha-switchbot-remote/issues", "iot_class": "cloud_push", "requirements": [ "pyhumps" ], - "version": "0.0.1-alfa.2" + "version": "1.0.0" } \ No newline at end of file diff --git a/custom_components/switchbotremote/media_player.py b/custom_components/switchbotremote/media_player.py index 8727376..7dfdd39 100644 --- a/custom_components/switchbotremote/media_player.py +++ b/custom_components/switchbotremote/media_player.py @@ -16,7 +16,7 @@ from homeassistant.helpers.event import async_track_state_change from .client.remote import SupportedRemote -from .const import DOMAIN, MEDIA_CLASS, IR_MEDIA_TYPES, DIY_PROJECTOR_TYPE, PROJECTOR_TYPE +from .const import DOMAIN, MEDIA_CLASS, IR_MEDIA_TYPES, DIY_PROJECTOR_TYPE, PROJECTOR_TYPE, CONF_POWER_SENSOR _LOGGER = logging.getLogger(__name__) @@ -32,6 +32,7 @@ PROJECTOR_TYPE, ] + class SwitchbotRemoteMediaPlayer(MediaPlayerEntity, RestoreEntity): _attr_has_entity_name = False @@ -45,7 +46,7 @@ def __init__(self, hass: HomeAssistant, sb: SupportedRemote, options: dict = {}) self._state = STATE_OFF self._source = None - self._power_sensor = options.get("power_sensor", None) + self._power_sensor = options.get(CONF_POWER_SENSOR, None) self._supported_features = MediaPlayerEntityFeature.TURN_ON | MediaPlayerEntityFeature.TURN_OFF self._supported_features |= MediaPlayerEntityFeature.VOLUME_STEP @@ -247,7 +248,8 @@ async def async_added_to_hass(self): await super().async_added_to_hass() if self._power_sensor: - async_track_state_change(self.hass, self._power_sensor, self._async_power_sensor_changed) + async_track_state_change( + self.hass, self._power_sensor, self._async_power_sensor_changed) power_sensor_state = self.hass.states.get(self._power_sensor) if power_sensor_state and power_sensor_state.state != STATE_UNKNOWN: diff --git a/custom_components/switchbotremote/remote.py b/custom_components/switchbotremote/remote.py index 1a7727a..5363d8c 100644 --- a/custom_components/switchbotremote/remote.py +++ b/custom_components/switchbotremote/remote.py @@ -9,10 +9,11 @@ from homeassistant.const import STATE_UNAVAILABLE, STATE_UNKNOWN, STATE_OFF, STATE_ON from .client.remote import SupportedRemote -from .const import DOMAIN, OTHERS_TYPE, CLASS_BY_TYPE +from .const import DOMAIN, OTHERS_TYPE, CLASS_BY_TYPE, CONF_POWER_SENSOR, CONF_ON_COMMAND, CONF_OFF_COMMAND _LOGGER = logging.getLogger(__name__) + class SwitchBotRemoteOther(RemoteEntity, RestoreEntity): _attr_has_entity_name = False @@ -23,9 +24,9 @@ def __init__(self, sb: SupportedRemote, options: dict = {}) -> None: self._attr_unique_id = sb.id self._is_on = False - self._power_sensor = options.get("power_sensor", None) - self._on_command = options.get("on_command", None) - self._off_command = options.get("off_command", None) + self._power_sensor = options.get(CONF_POWER_SENSOR, None) + self._on_command = options.get(CONF_ON_COMMAND, None) + self._off_command = options.get(CONF_OFF_COMMAND, None) @property def device_info(self): @@ -79,7 +80,8 @@ async def async_added_to_hass(self): await super().async_added_to_hass() if self._power_sensor: - async_track_state_change(self.hass, self._power_sensor, self._async_power_sensor_changed) + async_track_state_change( + self.hass, self._power_sensor, self._async_power_sensor_changed) power_sensor_state = self.hass.states.get(self._power_sensor) if power_sensor_state and power_sensor_state.state != STATE_UNKNOWN: diff --git a/custom_components/switchbotremote/translations/en.json b/custom_components/switchbotremote/translations/en.json index bcb6c07..cbbbb6e 100644 --- a/custom_components/switchbotremote/translations/en.json +++ b/custom_components/switchbotremote/translations/en.json @@ -39,6 +39,7 @@ "humidity_sensor": "Humidity sensor ID to be used as air conditioner actual humidity", "power_sensor": "Power sensor ID to get device status", "customize_commands": "Button names (case sensitive)", + "hvac_modes": "Supported modes", "temp_min": "Minimum temperature", "temp_max": "Maximum temperature", "temp_step": "Temperature step factor", diff --git a/custom_components/switchbotremote/translations/es.json b/custom_components/switchbotremote/translations/es.json index 225e193..f9eecbb 100644 --- a/custom_components/switchbotremote/translations/es.json +++ b/custom_components/switchbotremote/translations/es.json @@ -39,6 +39,7 @@ "humidity_sensor": "ID del sensor de humedad que se utilizará como humedad real del aire acondicionado", "power_sensor": "ID del sensor de encendido para obtener el estado del dispositivo", "customize_commands": "Nombre de botones (distingue mayúsculas y minúsculas)", + "hvac_modes": "Modos soportados", "temp_min": "Temperatura mínima", "temp_max": "Temperatura máxima", "temp_step": "Factor de pasos en temperatura", diff --git a/custom_components/switchbotremote/translations/it.json b/custom_components/switchbotremote/translations/it.json index 1c76095..b939696 100644 --- a/custom_components/switchbotremote/translations/it.json +++ b/custom_components/switchbotremote/translations/it.json @@ -39,6 +39,7 @@ "humidity_sensor": "ID sensore umidità da utilizzare", "power_sensor": "ID sensore per indicare se dispositivo è accesa o spenta", "customize_commands": "Nomi dei pulsanti (maiuscole e minuscole)", + "hvac_modes": "Modalità supportate", "temp_min": "Temperatura minima", "temp_max": "Temperatura massima", "temp_step": "Fattore di incremento della temperatura", diff --git a/custom_components/switchbotremote/water_heater.py b/custom_components/switchbotremote/water_heater.py index edc58b5..67e482e 100644 --- a/custom_components/switchbotremote/water_heater.py +++ b/custom_components/switchbotremote/water_heater.py @@ -1,3 +1,4 @@ +from .const import DOMAIN, WATER_HEATER_CLASS, IR_WATER_HEATER_TYPES, CONF_POWER_SENSOR, CONF_TEMPERATURE_SENSOR, CONF_TEMP_MAX, CONF_TEMP_MIN import logging from typing import List from homeassistant.components.water_heater import WaterHeaterEntity, WaterHeaterEntityFeature, STATE_HEAT_PUMP @@ -11,11 +12,11 @@ _LOGGER = logging.getLogger(__name__) -from .const import DOMAIN, WATER_HEATER_CLASS, IR_WATER_HEATER_TYPES DEFAULT_MIN_TEMP = 40 DEFAULT_MAX_TEMP = 65 + class SwitchBotRemoteWaterHeater(WaterHeaterEntity, RestoreEntity): _attr_has_entity_name = False _attr_operation_list = [STATE_OFF, STATE_HEAT_PUMP] @@ -31,10 +32,10 @@ def __init__(self, sb: SupportedRemote, options: dict = {}) -> None: self._supported_features = WaterHeaterEntityFeature.OPERATION_MODE self._current_temperature = None - self._power_sensor = options.get("power_sensor", None) - self._temperature_sensor = options.get("temperature_sensor", None) - self._max_temp = options.get("temp_max", DEFAULT_MAX_TEMP) - self._min_temp = options.get("temp_min", DEFAULT_MIN_TEMP) + self._power_sensor = options.get(CONF_POWER_SENSOR, None) + self._temperature_sensor = options.get(CONF_TEMPERATURE_SENSOR, None) + self._max_temp = options.get(CONF_TEMP_MAX, DEFAULT_MAX_TEMP) + self._min_temp = options.get(CONF_TEMP_MIN, DEFAULT_MIN_TEMP) @property def device_info(self): @@ -148,14 +149,16 @@ async def async_added_to_hass(self): await super().async_added_to_hass() if self._temperature_sensor: - async_track_state_change(self.hass, self._temperature_sensor, self._async_temp_sensor_changed) + async_track_state_change( + self.hass, self._temperature_sensor, self._async_temp_sensor_changed) temp_sensor_state = self.hass.states.get(self._temperature_sensor) if temp_sensor_state and temp_sensor_state.state != STATE_UNKNOWN: self._async_update_temp(temp_sensor_state) if self._power_sensor: - async_track_state_change(self.hass, self._power_sensor, self._async_power_sensor_changed) + async_track_state_change( + self.hass, self._power_sensor, self._async_power_sensor_changed) power_sensor_state = self.hass.states.get(self._power_sensor) if power_sensor_state and power_sensor_state.state != STATE_UNKNOWN: diff --git a/hacs.json b/hacs.json index 4b2c716..50e40e0 100644 --- a/hacs.json +++ b/hacs.json @@ -1,5 +1,4 @@ { "name": "SwitchBot Remote IR", - "render_readme": true, - "iot_class": "cloud_push" + "render_readme": true }