Skip to content

Commit 5607a97

Browse files
authored
Merge pull request #96 from bhamiltoncx/Core200S
Add support for Dual 200S humidifier device
2 parents a157537 + c80bfbc commit 5607a97

File tree

5 files changed

+55
-32
lines changed

5 files changed

+55
-32
lines changed

azure-pipelines.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ pr:
1414

1515
jobs:
1616
- job: 'Validation'
17+
pool:
18+
vmImage: 'ubuntu-20.04'
1719
steps:
1820
- task: UsePythonVersion@0
1921
inputs:
@@ -39,7 +41,7 @@ jobs:
3941
4042
- job: 'pytest'
4143
pool:
42-
vmImage: 'ubuntu-latest'
44+
vmImage: 'ubuntu-20.04'
4345
strategy:
4446
matrix:
4547
Python36:

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
setup(
1212
name='pyvesync',
13-
version='1.4.1',
13+
version='1.4.2',
1414
description='pyvesync is a library to manage Etekcity\
1515
Devices and Levoit Air Purifier',
1616
long_description=long_description,

src/pyvesync/vesync.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@
55
import time
66
from itertools import chain
77
from collections import defaultdict
8-
from typing import List, Dict, DefaultDict, Union, Any
8+
from typing import List, Dict, DefaultDict, Union, Any, Type
99

1010
from pyvesync.helpers import Helpers
11+
from pyvesync.vesyncbasedevice import VeSyncBaseDevice
1112
from pyvesync.vesyncbulb import VeSyncBulbESL100, VeSyncBulbESL100CW
1213
from pyvesync.vesyncfan import (
1314
VeSyncAir131,
14-
VeSyncHumid300S,
15+
VeSyncHumid200300S,
1516
VeSyncAir200S,
1617
VeSyncAir300S400S,
1718
)
@@ -32,7 +33,7 @@
3233

3334
# Class dictionary based on device type
3435

35-
_DEVICE_CLASS: Dict[str, Any] = {
36+
_DEVICE_CLASS: Dict[str, Type[VeSyncBaseDevice]] = {
3637
'wifi-switch-1.3': VeSyncOutlet7A,
3738
'ESW03-USA': VeSyncOutlet10A,
3839
'ESW01-EU': VeSyncOutlet10A,
@@ -44,7 +45,8 @@
4445
'ESL100': VeSyncBulbESL100,
4546
'ESL100CW': VeSyncBulbESL100CW,
4647
'ESWD16': VeSyncDimmerSwitch,
47-
'Classic300S': VeSyncHumid300S,
48+
'Classic300S': VeSyncHumid200300S,
49+
'Dual200S': VeSyncHumid200300S,
4850
'Core200S': VeSyncAir200S,
4951
'Core300S': VeSyncAir300S400S,
5052
'Core400S': VeSyncAir300S400S,
@@ -54,7 +56,8 @@
5456
outlets=['wifi-switch-1.3', 'ESW03-USA',
5557
'ESW01-EU', 'ESW15-USA', 'ESO15-TB'],
5658
switches=['ESWL01', 'ESWL03', 'ESWD16'],
57-
fans=['LV-PUR131S', 'Classic300S', 'Core200S', 'Core300S', 'Core400S'],
59+
fans=['LV-PUR131S', 'Classic300S', 'Core200S',
60+
'Core300S', 'Core400S', 'Dual200S'],
5861
bulbs=['ESL100', 'ESL100CW'],
5962
)
6063

src/pyvesync/vesyncbasedevice.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,10 @@ def __hash__(self):
5252

5353
def __str__(self):
5454
"""Use device info for string represtation of class."""
55-
return f'Device Name: {self.device_name}, Device Type: {self.device_type},\
56-
SubDevice No.: {self.sub_device_no} Status: {self.device_status}'
55+
return f'Device Name: {self.device_name}, \
56+
Device Type: {self.device_type},\
57+
SubDevice No.: {self.sub_device_no},\
58+
Status: {self.device_status}'
5759

5860
def __repr__(self):
5961
"""Representation of device details."""

src/pyvesync/vesyncfan.py

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
from pyvesync.vesyncbasedevice import VeSyncBaseDevice
88
from pyvesync.helpers import Helpers
99

10+
air_features = {
11+
'Dual200S': [],
12+
'Classic300S': ['nightlight']
13+
}
1014

1115
logger = logging.getLogger(__name__)
1216

@@ -1059,13 +1063,17 @@ def displayJSON(self) -> str:
10591063
return sup_val
10601064

10611065

1062-
class VeSyncHumid300S(VeSyncBaseDevice):
1063-
"""300S Humidifier Class."""
1066+
class VeSyncHumid200300S(VeSyncBaseDevice):
1067+
"""200S/300S Humidifier Class."""
10641068

10651069
def __init__(self, details, manager):
1066-
"""Initilize 300S Humidifier class."""
1070+
"""Initialize 200S/300S Humidifier class."""
10671071
super().__init__(details, manager)
10681072
self.enabled = True
1073+
if 'nightlight' in air_features.get(details['deviceType']):
1074+
self.night_light = True
1075+
else:
1076+
self.night_light = False
10691077
self.details: Dict[str, Union[str, int, float]] = {
10701078
'humidity': 0,
10711079
'mist_virtual_level': 0,
@@ -1076,16 +1084,17 @@ def __init__(self, details, manager):
10761084
'water_tank_lifted': False,
10771085
'display': False,
10781086
'automatic_stop_reach_target': False,
1079-
'night_light_brightness': 0
10801087
}
1088+
if self.night_light:
1089+
self.details['night_light_brightness'] = 0
10811090
self.config: Dict[str, Union[str, int, float]] = {
10821091
'auto_target_humidity': 0,
10831092
'display': False,
10841093
'automatic_stop': True
10851094
}
10861095

10871096
def __build_api_dict(self, method: str) -> Tuple[Dict, Dict]:
1088-
"""Build 300S api call header and body.
1097+
"""Build 200S/300S api call header and body.
10891098
10901099
Available methods are: 'getHumidifierStatus', 'setAutomaticStop',
10911100
'setSwitch', 'setNightLightBrightness', 'setVirtualLevel',
@@ -1108,7 +1117,7 @@ def __build_api_dict(self, method: str) -> Tuple[Dict, Dict]:
11081117
return head, body
11091118

11101119
def build_humid_dict(self, dev_dict: Dict):
1111-
"""Build 300S humidifier status dictionary."""
1120+
"""Build 200S/300S humidifier status dictionary."""
11121121
self.enabled = dev_dict.get('enabled')
11131122
self.details['humidity'] = dev_dict.get('humidity', 0)
11141123
self.details['mist_virtual_level'] = dev_dict.get(
@@ -1123,8 +1132,9 @@ def build_humid_dict(self, dev_dict: Dict):
11231132
self.details['automatic_stop_reach_target'] = dev_dict.get(
11241133
'automatic_stop_reach_target', True
11251134
)
1126-
self.details['night_light_brightness'] = dev_dict.get(
1127-
'night_light_brightness', 0)
1135+
if self.night_light:
1136+
self.details['night_light_brightness'] = dev_dict.get(
1137+
'night_light_brightness', 0)
11281138

11291139
def build_config_dict(self, conf_dict):
11301140
"""Build configuration dict for 300s humidifier."""
@@ -1134,7 +1144,7 @@ def build_config_dict(self, conf_dict):
11341144
self.config['automatic_stop'] = conf_dict.get('automatic_stop', True)
11351145

11361146
def get_details(self) -> None:
1137-
"""Build 300S Humidifier details dictionary."""
1147+
"""Build 200S/300S Humidifier details dictionary."""
11381148
head = Helpers.bypass_header()
11391149
body = Helpers.bypass_body_v2(self.manager)
11401150
body['cid'] = self.cid
@@ -1169,7 +1179,7 @@ def get_details(self) -> None:
11691179
logger.debug('Error in humidifier response')
11701180

11711181
def update(self):
1172-
"""Update 300S Humidifier details."""
1182+
"""Update 200S/300S Humidifier details."""
11731183
self.get_details()
11741184

11751185
def toggle_switch(self, toggle: bool) -> bool:
@@ -1204,23 +1214,23 @@ def toggle_switch(self, toggle: bool) -> bool:
12041214
return False
12051215

12061216
def turn_on(self) -> bool:
1207-
"""Turn 300S Humidifier on."""
1217+
"""Turn 200S/300S Humidifier on."""
12081218
return self.toggle_switch(True)
12091219

12101220
def turn_off(self):
1211-
"""Turn 300S Humidifier off."""
1221+
"""Turn 200S/300S Humidifier off."""
12121222
return self.toggle_switch(False)
12131223

12141224
def automatic_stop_on(self) -> bool:
1215-
"""Turn 300S Humidifier automatic stop on."""
1225+
"""Turn 200S/300S Humidifier automatic stop on."""
12161226
return self.set_automatic_stop(True)
12171227

12181228
def automatic_stop_off(self) -> bool:
1219-
"""Turn 300S Humidifier automatic stop on."""
1229+
"""Turn 200S/300S Humidifier automatic stop on."""
12201230
return self.set_automatic_stop(False)
12211231

12221232
def set_automatic_stop(self, mode: bool) -> bool:
1223-
"""Set 300S Humidifier to automatic stop."""
1233+
"""Set 200S/300S Humidifier to automatic stop."""
12241234
if mode not in (True, False):
12251235
logger.debug(
12261236
'Invalid mode passed to set_automatic_stop - %s', mode)
@@ -1274,15 +1284,15 @@ def set_display(self, mode: bool) -> bool:
12741284
return False
12751285

12761286
def turn_on_display(self) -> bool:
1277-
"""Turn 300S Humidifier on."""
1287+
"""Turn 200S/300S Humidifier on."""
12781288
return self.set_display(True)
12791289

12801290
def turn_off_display(self):
1281-
"""Turn 300S Humidifier off."""
1291+
"""Turn 200S/300S Humidifier off."""
12821292
return self.set_display(False)
12831293

12841294
def set_humidity(self, humidity: int) -> bool:
1285-
"""Set target 300S Humidifier humidity."""
1295+
"""Set target 200S/300S Humidifier humidity."""
12861296
if humidity < 30 or humidity > 80:
12871297
logger.debug("Humidity value must be set between 30 and 80")
12881298
return False
@@ -1308,7 +1318,11 @@ def set_humidity(self, humidity: int) -> bool:
13081318
return False
13091319

13101320
def set_night_light_brightness(self, brightness: int) -> bool:
1311-
"""Set target 300S Humidifier night light brightness."""
1321+
"""Set target 200S/300S Humidifier night light brightness."""
1322+
if not self.night_light:
1323+
logger.debug('%s is a %s does not have a nightlight',
1324+
self.device_name, self.device_type)
1325+
return False
13121326
if brightness < 0 or brightness > 100:
13131327
logger.debug("Brightness value must be set between 0 and 100")
13141328
return False
@@ -1400,12 +1414,13 @@ def display(self) -> None:
14001414
('Display: ', self.details['display'], ''),
14011415
('Automatic Stop Reach Target: ',
14021416
self.details['automatic_stop_reach_target'], ''),
1403-
('Night Light Brightness: ',
1404-
self.details['night_light_brightness'], 'percent'),
14051417
('Auto Target Humidity: ',
14061418
self.config['auto_target_humidity'], 'percent'),
14071419
('Automatic Stop: ', self.config['automatic_stop'], ''),
14081420
]
1421+
if self.night_light:
1422+
disp1.append(('Night Light Brightness: ',
1423+
self.details['night_light_brightness'], 'percent'))
14091424
for line in disp1:
14101425
print(f'{line[0]:.<29} {line[1]} {line[2]}')
14111426

@@ -1426,11 +1441,12 @@ def displayJSON(self) -> str:
14261441
'Display': self.details['display'],
14271442
'Automatic Stop Reach Target': self.details[
14281443
'automatic_stop_reach_target'],
1429-
'Night Light Brightness': self.details[
1430-
'night_light_brightness'],
14311444
'Auto Target Humidity': str(self.config[
14321445
'auto_target_humidity']),
14331446
'Automatic Stop': self.config['automatic_stop'],
14341447
}
14351448
)
1449+
if self.night_light:
1450+
sup_val['Night Light Brightness'] = self.details[
1451+
'night_light_brightness']
14361452
return json.dumps(sup_val)

0 commit comments

Comments
 (0)