Skip to content

Commit

Permalink
Add air purifier
Browse files Browse the repository at this point in the history
  • Loading branch information
mark86092 committed Jan 30, 2024
1 parent bcce205 commit f16d6e1
Show file tree
Hide file tree
Showing 6 changed files with 218 additions and 1 deletion.
4 changes: 4 additions & 0 deletions README-zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ _完整的實體清單請見 [可用的實體](#可用的實體)_
| | sensor | 運轉狀態偵測器 |
| | sensor | 洗衣模式偵測器 |
| | sensor | 洗衣行程偵測器 |
| 空氣清淨機 | switch | 電源開關 |
| | select | 風量設定\* |
| | switch | nanoeX 開關\* |
| | sensor | PM2.5 偵測器 |

\*僅在裝置支援的情況下可用

Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ See [支援的裝置 / Supported devices](https://github.com/osk2/panasonic_smar
| | sensor | Device status sensor |
| | sensor | Washing mode sensor |
| | sensor | Washing cycle sensor |
| Purifier | switch | Power switch |
| | select | Fan level\* |
| | switch | nanoeX switch\* |
| | sensor | PM2.5 sensor |

\*Only available if the feature is supported.

Expand Down
12 changes: 12 additions & 0 deletions custom_components/panasonic_smart_app/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
DEVICE_TYPE_AC = 1
DEVICE_TYPE_WASHING_MACHINE = 3
DEVICE_TYPE_DEHUMIDIFIER = 4
DEVICE_TYPE_PURIFIER = 8

DATA_CLIENT = "client"
DATA_COORDINATOR = "coordinator"
Expand Down Expand Up @@ -85,6 +86,12 @@
"0x61", # Washing machine dryer delay
"0x64", # Washing machine cycle
],
DEVICE_TYPE_PURIFIER: [
"0x00", # Purifier power status
"0x01", # Purifier fan level
"0x07", # Purifier nanoeX
"0x50", # Purifier PM 2.5
],
}

DEHUMIDIFIER_MAX_HUMD = 70
Expand Down Expand Up @@ -135,6 +142,7 @@
ICON_THERMOMETER = "mdi:thermometer"
ICON_PM25 = "mdi:dots-hexagon"
ICON_NANOE = "mdi:atom"
ICON_NANOEX = "mdi:atom"
ICON_ECONAVI = "mdi:leaf"
ICON_BUZZER = "mdi:volume-high"
ICON_TURBO = "mdi:clock-fast"
Expand All @@ -150,6 +158,7 @@
ICON_INFO = "mdi:information"
ICON_WASHING_MACHINE = "mdi:washing-machine"
ICON_LIST = "mdi:order-bool-descending-variant"
ICON_PURIFIER = "mdi:air-purifier"

LABEL_DEHUMIDIFIER = ""
LABEL_CLIMATE = ""
Expand All @@ -172,12 +181,15 @@
LABEL_WASHING_MACHINE_CYCLE = "目前行程"
LABEL_WASHING_MACHINE_MODE = "目前模式"
LABEL_OUTDOOR_TEMPERATURE = "室外溫度"
LABEL_PURIFIER_FAN_LEVEL = "風量設定"
LABEL_PM25 = "PM2.5"
LABEL_NANOE = "nanoe"
LABEL_NANOEX = "nanoeX"
LABEL_ECONAVI = "ECONAVI"
LABEL_BUZZER = "操作提示音"
LABEL_TURBO = "急速"
LABEL_ENERGY = "本月耗電量"
LABEL_POWER = "電源"

UNIT_HOUR = "小時"
UNIT_MINUTE = "分鐘"
Expand Down
70 changes: 69 additions & 1 deletion custom_components/panasonic_smart_app/select.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
DOMAIN,
DEVICE_TYPE_AC,
DEVICE_TYPE_DEHUMIDIFIER,
DEVICE_TYPE_PURIFIER,
DATA_CLIENT,
DATA_COORDINATOR,
LABEL_DEHUMIDIFIER_FAN_MODE,
LABEL_PURIFIER_FAN_LEVEL,
LABEL_CLIMATE_FAN_POSITION,
LABEL_CLIMATE_MOTION_DETECTION,
LABEL_CLIMATE_INDICATOR,
Expand Down Expand Up @@ -73,6 +75,17 @@ async def async_setup_entry(hass, entry, async_add_entities) -> bool:
)
)

if device_type == DEVICE_TYPE_PURIFIER:
if "0x01" in command_types:
select.append(
PanasonoicPurifierFanLevelSelect(
coordinator,
index,
client,
device,
)
)

async_add_entities(select, True)

return True
Expand Down Expand Up @@ -235,4 +248,59 @@ async def async_select_option(self, option: str) -> None:
await self.client.set_command(self.auth, 159, target_option[0][1])
await self.coordinator.async_request_refresh()
else:
return
return


class PanasonoicPurifierFanLevelSelect(PanasonicBaseEntity, SelectEntity):
_attr_has_entity_name = True

@property
def available(self) -> bool:
status = self.coordinator.data[self.index]["status"]
_is_on_status = bool(int(status.get("0x00", 0)))
return _is_on_status

@property
def label(self) -> str:
return LABEL_PURIFIER_FAN_LEVEL

@property
def icon(self) -> str:
return ICON_FAN

@property
def options(self) -> list:
raw_mode_list = list(
filter(lambda c: c["CommandType"] == "0x01", self.commands)
)[0]["Parameters"]

def mode_extractor(mode):
return mode[0]

mode_list = list(map(mode_extractor, raw_mode_list))
return mode_list

@property
def current_option(self) -> bool:
status = self.coordinator.data[self.index]["status"]
raw_mode_list = list(
filter(lambda c: c["CommandType"] == "0x01", self.commands)
)[0]["Parameters"]
target_option = list(
filter(lambda m: m[1] == int(status.get("0x01") or 0), raw_mode_list)
)[0]
_current_option = target_option[0] if len(target_option) > 0 else ""
_LOGGER.debug(f"[{self.label}] current_option: {_current_option}")
return _current_option

async def async_select_option(self, option: str) -> None:
raw_mode_list = list(
filter(lambda c: c["CommandType"] == "0x01", self.commands)
)[0]["Parameters"]
target_option = list(filter(lambda m: m[0] == option, raw_mode_list))
if len(target_option) > 0:
_LOGGER.debug(f"[{self.label}] Set fan mode to {option}")
await self.client.set_command(self.auth, 129, target_option[0][1])
await self.coordinator.async_request_refresh()
else:
return
20 changes: 20 additions & 0 deletions custom_components/panasonic_smart_app/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
DEVICE_TYPE_DEHUMIDIFIER,
DEVICE_TYPE_AC,
DEVICE_TYPE_WASHING_MACHINE,
DEVICE_TYPE_PURIFIER,
DATA_CLIENT,
DATA_COORDINATOR,
LABEL_PM25,
Expand Down Expand Up @@ -134,6 +135,16 @@ async def async_setup_entry(hass, entry, async_add_entities) -> bool:
)
)

if device_type == DEVICE_TYPE_PURIFIER:
sensors.append(
PanasonicPurifierPM25Sensor(
coordinator,
index,
client,
device,
)
)

async_add_entities(sensors, True)

return True
Expand Down Expand Up @@ -222,6 +233,15 @@ class PanasonicACPM25Sensor(PanasonicPM25Sensor):
def command_type(self) -> str:
return "0x37"


class PanasonicPurifierPM25Sensor(PanasonicPM25Sensor):
""" Panasonic Purifier PM2.5 sensor """

@property
def command_type(self) -> str:
return "0x50"


class PanasonicOutdoorTemperatureSensor(PanasonicBaseEntity, SensorEntity):
""" Panasonic AC outdoor temperature sensor """

Expand Down
109 changes: 109 additions & 0 deletions custom_components/panasonic_smart_app/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,28 @@
from .const import (
DOMAIN,
DEVICE_TYPE_AC,
DEVICE_TYPE_PURIFIER,
DATA_CLIENT,
DATA_COORDINATOR,
DEVICE_CLASS_SWITCH,
LABEL_NANOE,
LABEL_NANOEX,
LABEL_ECONAVI,
LABEL_BUZZER,
LABEL_TURBO,
LABEL_CLIMATE_MOLD_PREVENTION,
LABEL_CLIMATE_SLEEP,
LABEL_CLIMATE_CLEAN,
LABEL_POWER,
ICON_NANOE,
ICON_NANOEX,
ICON_ECONAVI,
ICON_BUZZER,
ICON_TURBO,
ICON_SLEEP,
ICON_MOLD_PREVENTION,
ICON_CLEAN,
ICON_PURIFIER,
)

_LOGGER = logging.getLogger(__package__)
Expand Down Expand Up @@ -113,6 +118,26 @@ async def async_setup_entry(hass, entry, async_add_entities) -> bool:
)
)

if device_type == DEVICE_TYPE_PURIFIER:
if "0x00" in command_types:
switches.append(
PanasonicPurifierPower(
coordinator,
index,
client,
device,
)
)
if "0x07" in command_types:
switches.append(
PanasonicPurifierNanoeX(
coordinator,
index,
client,
device,
)
)

async_add_entities(switches, True)

return True
Expand Down Expand Up @@ -410,3 +435,87 @@ async def async_turn_off(self) -> None:
_LOGGER.debug(f"[{self.label}] Turning off self clean")
await self.client.set_command(self.auth, 24, 0)
await self.coordinator.async_request_refresh()


class PanasonicPurifierPower(PanasonicBaseEntity, SwitchEntity):
""" Panasonic Purifier power """

@property
def available(self) -> bool:
status = self.coordinator.data[self.index]["status"]
return status.get("0x00", None) != None

@property
def label(self):
return LABEL_POWER

@property
def icon(self) -> str:
return ICON_PURIFIER

@property
def device_class(self) -> str:
return DEVICE_CLASS_SWITCH

@property
def is_on(self) -> int:
status = self.coordinator.data[self.index]["status"]
_power_status = status.get("0x00")
if _power_status == None:
return STATE_UNAVAILABLE
_is_on = bool(int(_power_status))
_LOGGER.debug(f"[{self.label}] is_on: {_is_on}")
return _is_on

async def async_turn_on(self) -> None:
_LOGGER.debug(f"[{self.label}] Turning on nanoeX")
await self.client.set_command(self.auth, 128, 1)
await self.coordinator.async_request_refresh()

async def async_turn_off(self) -> None:
_LOGGER.debug(f"[{self.label}] Turning off nanoeX")
await self.client.set_command(self.auth, 128, 0)
await self.coordinator.async_request_refresh()



class PanasonicPurifierNanoeX(PanasonicBaseEntity, SwitchEntity):
""" Panasonic Purifier nanoeX switch """

@property
def available(self) -> bool:
status = self.coordinator.data[self.index]["status"]
_is_on_status = bool(int(status.get("0x00", 0)))
return _is_on_status

@property
def label(self):
return f"{self.nickname} {LABEL_NANOEX}"

@property
def icon(self) -> str:
return ICON_NANOEX

@property
def device_class(self) -> str:
return DEVICE_CLASS_SWITCH

@property
def is_on(self) -> int:
status = self.coordinator.data[self.index]["status"]
_nanoe_status = status.get("0x07")
if _nanoe_status == None:
return STATE_UNAVAILABLE
_is_on = bool(int(_nanoe_status))
_LOGGER.debug(f"[{self.label}] is_on: {_is_on}")
return _is_on

async def async_turn_on(self) -> None:
_LOGGER.debug(f"[{self.label}] Turning on nanoeX")
await self.client.set_command(self.auth, 135, 1)
await self.coordinator.async_request_refresh()

async def async_turn_off(self) -> None:
_LOGGER.debug(f"[{self.label}] Turning off nanoeX")
await self.client.set_command(self.auth, 135, 0)
await self.coordinator.async_request_refresh()

0 comments on commit f16d6e1

Please sign in to comment.