Skip to content

Commit

Permalink
Merge pull request #262 from itsnotrin/master
Browse files Browse the repository at this point in the history
Add support for BSDGO1 smart plug / outlet.
  • Loading branch information
webdjoe authored Jan 16, 2025
2 parents 736c292 + b35365a commit 171b133
Show file tree
Hide file tree
Showing 10 changed files with 471 additions and 52 deletions.
71 changes: 68 additions & 3 deletions src/pyvesync/vesyncoutlet.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
'module': 'VeSyncOutlet15A'},
'ESO15-TB': {
'module': 'VeSyncOutdoorPlug'},
'BSDOG01': {
'module': 'VeSyncOutletBSDGO1'},
}

outlet_modules = {k: v['module'] for k, v in outlet_config.items()}
Expand Down Expand Up @@ -573,7 +575,6 @@ def turn_off(self) -> bool:
if Helpers.code_check(response):
self.device_status = 'off'
return True

logger.warning('Error turning %s off', self.device_name)
return False

Expand Down Expand Up @@ -733,9 +734,73 @@ def toggle(self, status) -> bool:
return False

def turn_on(self) -> bool:
"""Turn outdoor outlet on and return True if successful."""
"""Turn on outlet."""
return bool(self.toggle('on'))

def turn_off(self) -> bool:
"""Turn outdoor outlet off and return True if successful."""
"""Turn off outlet."""
return bool(self.toggle('off'))


class VeSyncOutletBSDGO1(VeSyncOutlet):
"""VeSync BSDGO1 smart plug."""

def __init__(self, details, manager):
"""Initialize BSDGO1 smart plug class."""
super().__init__(details, manager)

def get_details(self) -> None:
"""Get BSDGO1 device details."""
body = Helpers.req_body(self.manager, 'bypassV2')
body['cid'] = self.cid
body['configModule'] = self.config_module
body['payload'] = {
'method': 'getProperty',
'source': 'APP',
'data': {}
}

r, _ = Helpers.call_api(
'/cloud/v2/deviceManaged/bypassV2',
'post',
headers=Helpers.req_header_bypass(),
json_object=body,
)

if Helpers.code_check(r):
self.device_status = 'on' if r.get('result', {}).get(
'powerSwitch_1') == 1 else 'off'
else:
logger.debug('Error getting %s details', self.device_name)

def turn_on(self) -> bool:
"""Turn BSDGO1 outlet on."""
return self._set_power(True)

def turn_off(self) -> bool:
"""Turn BSDGO1 outlet off."""
return self._set_power(False)

def _set_power(self, power: bool) -> bool:
"""Set power state of BSDGO1 outlet."""
body = Helpers.req_body(self.manager, 'bypassV2')
body['cid'] = self.cid
body['configModule'] = self.config_module
body['payload'] = {
'data': {'powerSwitch_1': 1 if power else 0},
'method': 'setProperty',
'source': 'APP'
}

r, _ = Helpers.call_api(
'/cloud/v2/deviceManaged/bypassV2',
'post',
headers=Helpers.req_header_bypass(),
json_object=body,
)

if Helpers.code_check(r):
self.device_status = 'on' if power else 'off'
return True
logger.warning('Error turning %s %s', self.device_name, 'on' if power else 'off')
return False
94 changes: 94 additions & 0 deletions src/tests/api/vesyncoutlet/BSDOG01.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
get_details:
headers:
Content-Type: application/json; charset=UTF-8
User-Agent: okhttp/3.12.1
json_object:
acceptLanguage: en
accountID: sample_id
appVersion: 2.8.6
cid: BSDOG01-CID
configModule: ConfigModule
deviceRegion: US
method: bypassV2
payload:
data: {}
method: getProperty
source: APP
phoneBrand: SM N9005
phoneOS: Android
timeZone: America/New_York
token: sample_tk
traceId: TRACE_ID
method: post
url: /cloud/v2/deviceManaged/bypassV2
turn_off:
headers:
Content-Type: application/json; charset=UTF-8
User-Agent: okhttp/3.12.1
json_object:
acceptLanguage: en
accountID: sample_id
appVersion: 2.8.6
cid: BSDOG01-CID
configModule: ConfigModule
deviceRegion: US
method: bypassV2
payload:
data:
powerSwitch_1: 0
method: setProperty
source: APP
phoneBrand: SM N9005
phoneOS: Android
timeZone: America/New_York
token: sample_tk
traceId: TRACE_ID
method: post
url: /cloud/v2/deviceManaged/bypassV2
turn_on:
headers:
Content-Type: application/json; charset=UTF-8
User-Agent: okhttp/3.12.1
json_object:
acceptLanguage: en
accountID: sample_id
appVersion: 2.8.6
cid: BSDOG01-CID
configModule: ConfigModule
deviceRegion: US
method: bypassV2
payload:
data:
powerSwitch_1: 1
method: setProperty
source: APP
phoneBrand: SM N9005
phoneOS: Android
timeZone: America/New_York
token: sample_tk
traceId: TRACE_ID
method: post
url: /cloud/v2/deviceManaged/bypassV2
update:
headers:
Content-Type: application/json; charset=UTF-8
User-Agent: okhttp/3.12.1
json_object:
acceptLanguage: en
accountID: sample_id
appVersion: 2.8.6
cid: BSDOG01-CID
configModule: ConfigModule
deviceRegion: US
method: bypassV2
payload:
data: {}
method: getProperty
source: APP
phoneBrand: SM N9005
phoneOS: Android
timeZone: America/New_York
token: sample_tk
traceId: TRACE_ID
method: post
url: /cloud/v2/deviceManaged/bypassV2
22 changes: 22 additions & 0 deletions src/tests/api/vesyncoutlet/ESO15-TB.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,25 @@
get_details:
headers:
accept-language: en
accountId: sample_id
appVersion: 2.8.6
content-type: application/json
tk: sample_tk
tz: America/New_York
json_object:
acceptLanguage: en
accountID: sample_id
appVersion: 2.8.6
method: devicedetail
mobileId: '1234567890123456'
phoneBrand: SM N9005
phoneOS: Android
timeZone: America/New_York
token: sample_tk
traceId: TRACE_ID
uuid: ESO15-TB-UUID
method: post
url: /outdoorsocket15a/v1/device/devicedetail
get_monthly_energy:
headers:
accept-language: en
Expand Down
22 changes: 22 additions & 0 deletions src/tests/api/vesyncoutlet/ESW01-EU.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,25 @@
get_details:
headers:
accept-language: en
accountId: sample_id
appVersion: 2.8.6
content-type: application/json
tk: sample_tk
tz: America/New_York
json_object:
acceptLanguage: en
accountID: sample_id
appVersion: 2.8.6
method: devicedetail
mobileId: '1234567890123456'
phoneBrand: SM N9005
phoneOS: Android
timeZone: America/New_York
token: sample_tk
traceId: TRACE_ID
uuid: ESW01-EU-UUID
method: post
url: /10a/v1/device/devicedetail
get_monthly_energy:
headers:
accept-language: en
Expand Down
22 changes: 22 additions & 0 deletions src/tests/api/vesyncoutlet/ESW03-USA.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,25 @@
get_details:
headers:
accept-language: en
accountId: sample_id
appVersion: 2.8.6
content-type: application/json
tk: sample_tk
tz: America/New_York
json_object:
acceptLanguage: en
accountID: sample_id
appVersion: 2.8.6
method: devicedetail
mobileId: '1234567890123456'
phoneBrand: SM N9005
phoneOS: Android
timeZone: America/New_York
token: sample_tk
traceId: TRACE_ID
uuid: ESW03-USA-UUID
method: post
url: /10a/v1/device/devicedetail
get_monthly_energy:
headers:
accept-language: en
Expand Down
22 changes: 22 additions & 0 deletions src/tests/api/vesyncoutlet/ESW15-USA.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,25 @@
get_details:
headers:
accept-language: en
accountId: sample_id
appVersion: 2.8.6
content-type: application/json
tk: sample_tk
tz: America/New_York
json_object:
acceptLanguage: en
accountID: sample_id
appVersion: 2.8.6
method: devicedetail
mobileId: '1234567890123456'
phoneBrand: SM N9005
phoneOS: Android
timeZone: America/New_York
token: sample_tk
traceId: TRACE_ID
uuid: ESW15-USA-UUID
method: post
url: /15a/v1/device/devicedetail
get_monthly_energy:
headers:
accept-language: en
Expand Down
10 changes: 10 additions & 0 deletions src/tests/api/vesyncoutlet/wifi-switch-1.3.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
get_details:
headers:
accept-language: en
accountId: sample_id
appVersion: 2.8.6
content-type: application/json
tk: sample_tk
tz: America/New_York
method: get
url: /v1/device/wifi-switch-1.3-CID/detail
get_monthly_energy:
headers:
accept-language: en
Expand Down
28 changes: 26 additions & 2 deletions src/tests/call_json_outlets.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,11 @@ def status_response(request_kwargs=None):
default dict but make sure to use `deepcopy` to avoid unintended side effects.
"""
from copy import deepcopy
from collections import defaultdict
from utils import FunctionResponses, Defaults
from pyvesync import vesyncoutlet
from pyvesync.vesyncoutlet import outlet_modules

OUTLETS = vesyncoutlet.outlet_modules.keys()
OUTLETS = outlet_modules.keys()
OUTLETS_NUM = len(OUTLETS)

# OUTLETS = ['wifi-switch-1.3', 'ESW03-USA', 'ESW01-EU', 'ESW15-USA', 'ESO15-TB']
Expand Down Expand Up @@ -129,13 +130,26 @@ class OutletDetails:
200,
)

bsdgo1_details = ({
"code": 0,
"msg": "request success",
"result": {
"powerSwitch_1": 1,
"traceId": "1735308365651",
"active_time": Defaults.active_time,
"connectionStatus": "online",
"code": 0
}
}, 200)


DETAILS_RESPONSES = {
'wifi-switch-1.3': OutletDetails.details_7a,
'ESW03-USA': OutletDetails.details_10a,
'ESW01-EU': OutletDetails.details_10a,
'ESW15-USA': OutletDetails.details_15a,
'ESO15-TB': OutletDetails.details_outdoor,
'BSDOG01': OutletDetails.bsdgo1_details
}

ENERGY_HISTORY = (
Expand All @@ -160,3 +174,13 @@ class OutletDetails:
METHOD_RESPONSES[k]['get_weekly_energy'] = ENERGY_HISTORY
METHOD_RESPONSES[k]['get_monthly_energy'] = ENERGY_HISTORY
METHOD_RESPONSES[k]['get_yearly_energy'] = ENERGY_HISTORY

# Add BSDGO1 specific responses
METHOD_RESPONSES['BSDOG01'] = defaultdict(lambda: ({
"code": 0,
"msg": "request success",
"result": {
"traceId": Defaults.trace_id,
"code": 0
}
}, 200))
Loading

0 comments on commit 171b133

Please sign in to comment.