Skip to content

Commit

Permalink
Fix iFan03 cloud control
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexxIT committed Jun 7, 2020
1 parent d4331a8 commit 40c9b88
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 54 deletions.
33 changes: 2 additions & 31 deletions custom_components/sonoff/fan.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,7 @@ async def async_setup_platform(hass, config, add_entities,
device = registry.devices[deviceid]
uiid = device.get('uiid')
# iFan02 and iFan03 have the same uiid!
if uiid == 'fan_light' or device.get('productModel') == 'iFan':
add_entities([SonoffFan03(registry, deviceid)])
elif channels == IFAN02_CHANNELS:
if uiid == 34 or uiid == 'fan_light':
# only channel 2 is used for switching
add_entities([SonoffFan02(registry, deviceid, [2])])
else:
Expand Down Expand Up @@ -94,7 +92,7 @@ def _is_on_list(self, state: dict) -> List[bool]:
def _update_handler(self, state: dict, attrs: dict):
self._attrs.update(attrs)

if state and 'switches' in state:
if 'switches' in state:
mask = self._is_on_list(state)
if mask[0]:
if not mask[1] and not mask[2]:
Expand Down Expand Up @@ -122,30 +120,3 @@ async def async_turn_on(self, speed: Optional[str] = None, **kwargs):

async def async_turn_off(self, **kwargs) -> None:
await self._turn_off()


class SonoffFan03(SonoffFanBase):
def _update_handler(self, state: dict, attrs: dict):
self._attrs.update(attrs)

if 'fan' in state:
if state['fan'] == 'on':
speed = state.get('speed', 1)
self._speed = self.speed_list[speed]
else:
self._speed = SPEED_OFF

self.schedule_update_ha_state()

async def async_set_speed(self, speed: str) -> None:
speed = self.speed_list.index(speed)
await self.registry.send(self.deviceid, {'fan': 'on', 'speed': speed})

async def async_turn_on(self, speed: Optional[str] = None, **kwargs):
if speed:
await self.async_set_speed(speed)
else:
await self.registry.send(self.deviceid, {'fan': 'on'})

async def async_turn_off(self, **kwargs) -> None:
await self.registry.send(self.deviceid, {'fan': 'off'})
23 changes: 1 addition & 22 deletions custom_components/sonoff/light.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@ async def async_setup_platform(hass, config, add_entities,
device = registry.devices[deviceid]

uiid = device.get('uiid')
if uiid == 'fan_light' or device.get('productModel') == 'iFan':
add_entities([SonoffFan03Light(registry, deviceid)])
elif uiid == 'light' or uiid == 44:
if uiid == 44 or uiid == 'light':
add_entities([SonoffD1(registry, deviceid)])
elif uiid == 59:
add_entities([SonoffLED(registry, deviceid)])
Expand All @@ -46,25 +44,6 @@ async def async_setup_platform(hass, config, add_entities,
add_entities([EWeLinkToggle(registry, deviceid, channels)])


class SonoffFan03Light(EWeLinkToggle):
def _update_handler(self, state: dict, attrs: dict):
self._attrs.update(attrs)

if 'light' in state:
self._is_on = state['light'] == 'on'

if 'sledOnline' in state:
self._sled_online = state['sledOnline']

self.schedule_update_ha_state()

async def async_turn_on(self, **kwargs) -> None:
await self.registry.send(self.deviceid, {'light': 'on'})

async def async_turn_off(self, **kwargs) -> None:
await self.registry.send(self.deviceid, {'light': 'off'})


class SonoffD1(EWeLinkToggle):
_brightness = 0

Expand Down
44 changes: 44 additions & 0 deletions custom_components/sonoff/sonoff_local.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,43 @@ def decrypt(payload: dict, devicekey: str):
return None


# iFan02 local and cloud API uses switches
# iFan03 local API uses light/fan/speed and cloud API uses switches :(
# https://github.com/AlexxIT/SonoffLAN/issues/30
# https://github.com/AlexxIT/SonoffLAN/issues/153


def ifan03to02(state) -> dict:
"""Convert incoming from iFan03."""
return {'switches': [
{'outlet': 0, 'switch': state['light']},
{'outlet': 1, 'switch': state['fan']},
{'outlet': 2, 'switch': 'on' if state['speed'] == 2 else 'off'},
{'outlet': 3, 'switch': 'on' if state['speed'] == 3 else 'off'},
]}


def ifan02to03(payload: dict) -> dict:
"""Convert outcoming to iFan03."""
payload = {d['outlet']: d['switch'] for d in payload['switches']}

if 0 in payload:
return {'light': payload[0]}

if 2 in payload and 3 in payload:
if payload[2] == 'on':
return {'fan': payload[1], 'speed': 2}
elif payload[3] == 'on':
return {'fan': payload[1], 'speed': 3}
else:
return {'fan': payload[1], 'speed': 1}

if 1 in payload:
return {'fan': payload[1]}

raise NotImplemented


class EWeLinkLocal:
_devices: dict = None
_handlers = None
Expand Down Expand Up @@ -148,6 +185,10 @@ def _zeroconf_handler(self, zeroconf: Zeroconf, service_type: str,
if state.get('temperature') == 0 and state.get('humidity') == 0:
del state['temperature'], state['humidity']

if properties['type'] == 'fan_light':
state = ifan03to02(state)
device['uiid'] = 'fan_light'

host = str(ipaddress.ip_address(info.addresses[0]))
# update every time device host change (alsow first time)
if device.get('host') != host:
Expand Down Expand Up @@ -203,6 +244,9 @@ async def check_offline(self, deviceid: str):
async def send(self, deviceid: str, data: dict, sequence: str, timeout=5):
device: dict = self._devices[deviceid]

if device['uiid'] == 'fan_light':
data = ifan02to03(data)

# cmd for D1 and RF Bridge 433
command = data.get('cmd') or next(iter(data))

Expand Down
2 changes: 1 addition & 1 deletion custom_components/sonoff/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def init_device_class(default_class: str = 'switch'):
'strip': switch4, # 4CH Pro R2, Micro!, iFan02!
'light': 'light', # D1
'rf': 'remote', # RF Bridge 433
'fan_light': ['light', 'fan'], # iFan03
'fan_light': ['light', {'fan': [2, 3, 4]}], # iFan03
})


Expand Down

0 comments on commit 40c9b88

Please sign in to comment.