Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 93 additions & 23 deletions homeassistant/components/binary_sensor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,30 +20,100 @@
SCAN_INTERVAL = timedelta(seconds=30)

ENTITY_ID_FORMAT = DOMAIN + '.{}'

# On means low, Off means normal
DEVICE_CLASS_BATTERY = 'battery'

# On means cold, Off means normal
DEVICE_CLASS_COLD = 'cold'

# On means connected, Off means disconnected
DEVICE_CLASS_CONNECTIVITY = 'connectivity'

# On means open, Off means closed
DEVICE_CLASS_DOOR = 'door'

# On means open, Off means closed
DEVICE_CLASS_GARAGE_DOOR = 'garage_door'

# On means gas detected, Off means no gas (clear)
DEVICE_CLASS_GAS = 'gas'

# On means hot, Off means normal
DEVICE_CLASS_HEAT = 'heat'

# On means light detected, Off means no light
DEVICE_CLASS_LIGHT = 'light'

# On means open (unlocked), Off means closed (locked)
DEVICE_CLASS_LOCK = 'lock'

# On means wet, Off means dry
DEVICE_CLASS_MOISTURE = 'moisture'

# On means motion detected, Off means no motion (clear)
DEVICE_CLASS_MOTION = 'motion'

# On means moving, Off means not moving (stopped)
DEVICE_CLASS_MOVING = 'moving'

# On means occupied, Off means not occupied (clear)
DEVICE_CLASS_OCCUPANCY = 'occupancy'

# On means open, Off means closed
DEVICE_CLASS_OPENING = 'opening'

# On means plugged in, Off means unplugged
DEVICE_CLASS_PLUG = 'plug'

# On means power detected, Off means no power
DEVICE_CLASS_POWER = 'power'

# On means home, Off means away
DEVICE_CLASS_PRESENCE = 'presence'

# On means problem detected, Off means no problem (OK)
DEVICE_CLASS_PROBLEM = 'problem'

# On means unsafe, Off means safe
DEVICE_CLASS_SAFETY = 'safety'

# On means smoke detected, Off means no smoke (clear)
DEVICE_CLASS_SMOKE = 'smoke'

# On means sound detected, Off means no sound (clear)
DEVICE_CLASS_SOUND = 'sound'

# On means vibration detected, Off means no vibration
DEVICE_CLASS_VIBRATION = 'vibration'

# On means open, Off means closed
DEVICE_CLASS_WINDOW = 'window'

DEVICE_CLASSES = [
'battery', # On means low, Off means normal
'cold', # On means cold, Off means normal
'connectivity', # On means connected, Off means disconnected
'door', # On means open, Off means closed
'garage_door', # On means open, Off means closed
'gas', # On means gas detected, Off means no gas (clear)
'heat', # On means hot, Off means normal
'light', # On means light detected, Off means no light
'lock', # On means open (unlocked), Off means closed (locked)
'moisture', # On means wet, Off means dry
'motion', # On means motion detected, Off means no motion (clear)
'moving', # On means moving, Off means not moving (stopped)
'occupancy', # On means occupied, Off means not occupied (clear)
'opening', # On means open, Off means closed
'plug', # On means plugged in, Off means unplugged
'power', # On means power detected, Off means no power
'presence', # On means home, Off means away
'problem', # On means problem detected, Off means no problem (OK)
'safety', # On means unsafe, Off means safe
'smoke', # On means smoke detected, Off means no smoke (clear)
'sound', # On means sound detected, Off means no sound (clear)
'vibration', # On means vibration detected, Off means no vibration
'window', # On means open, Off means closed
DEVICE_CLASS_BATTERY,
DEVICE_CLASS_COLD,
DEVICE_CLASS_CONNECTIVITY,
DEVICE_CLASS_DOOR,
DEVICE_CLASS_GARAGE_DOOR,
DEVICE_CLASS_GAS,
DEVICE_CLASS_HEAT,
DEVICE_CLASS_LIGHT,
DEVICE_CLASS_LOCK,
DEVICE_CLASS_MOISTURE,
DEVICE_CLASS_MOTION,
DEVICE_CLASS_MOVING,
DEVICE_CLASS_OCCUPANCY,
DEVICE_CLASS_OPENING,
DEVICE_CLASS_PLUG,
DEVICE_CLASS_POWER,
DEVICE_CLASS_PRESENCE,
DEVICE_CLASS_PROBLEM,
DEVICE_CLASS_SAFETY,
DEVICE_CLASS_SMOKE,
DEVICE_CLASS_SOUND,
DEVICE_CLASS_VIBRATION,
DEVICE_CLASS_WINDOW,
]

DEVICE_CLASSES_SCHEMA = vol.All(vol.Lower, vol.In(DEVICE_CLASSES))
Expand Down
5 changes: 3 additions & 2 deletions homeassistant/components/google_assistant/smart_home.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from homeassistant.core import callback
from homeassistant.const import (
CLOUD_NEVER_EXPOSED_ENTITIES, CONF_NAME, STATE_UNAVAILABLE,
ATTR_SUPPORTED_FEATURES, ATTR_ENTITY_ID,
ATTR_SUPPORTED_FEATURES, ATTR_ENTITY_ID, ATTR_DEVICE_CLASS,
)
from homeassistant.components import (
camera,
Expand Down Expand Up @@ -92,10 +92,11 @@ def traits(self):
state = self.state
domain = state.domain
features = state.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
device_class = state.attributes.get(ATTR_DEVICE_CLASS)

self._traits = [Trait(self.hass, state, self.config)
for Trait in trait.TRAITS
if Trait.supported(domain, features)]
if Trait.supported(domain, features, device_class)]
return self._traits

async def sync_serialize(self):
Expand Down
49 changes: 34 additions & 15 deletions homeassistant/components/google_assistant/trait.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import logging

from homeassistant.components import (
binary_sensor,
camera,
cover,
group,
Expand Down Expand Up @@ -127,7 +128,7 @@ class BrightnessTrait(_Trait):
]

@staticmethod
def supported(domain, features):
def supported(domain, features, device_class):
"""Test if state is supported."""
if domain == light.DOMAIN:
return features & light.SUPPORT_BRIGHTNESS
Expand Down Expand Up @@ -193,7 +194,7 @@ class CameraStreamTrait(_Trait):
stream_info = None

@staticmethod
def supported(domain, features):
def supported(domain, features, device_class):
"""Test if state is supported."""
if domain == camera.DOMAIN:
return features & camera.SUPPORT_STREAM
Expand Down Expand Up @@ -236,7 +237,7 @@ class OnOffTrait(_Trait):
]

@staticmethod
def supported(domain, features):
def supported(domain, features, device_class):
"""Test if state is supported."""
return domain in (
group.DOMAIN,
Expand Down Expand Up @@ -285,7 +286,7 @@ class ColorSpectrumTrait(_Trait):
]

@staticmethod
def supported(domain, features):
def supported(domain, features, device_class):
"""Test if state is supported."""
if domain != light.DOMAIN:
return False
Expand Down Expand Up @@ -341,7 +342,7 @@ class ColorTemperatureTrait(_Trait):
]

@staticmethod
def supported(domain, features):
def supported(domain, features, device_class):
"""Test if state is supported."""
if domain != light.DOMAIN:
return False
Expand Down Expand Up @@ -414,7 +415,7 @@ class SceneTrait(_Trait):
]

@staticmethod
def supported(domain, features):
def supported(domain, features, device_class):
"""Test if state is supported."""
return domain in (scene.DOMAIN, script.DOMAIN)

Expand Down Expand Up @@ -450,7 +451,7 @@ class DockTrait(_Trait):
]

@staticmethod
def supported(domain, features):
def supported(domain, features, device_class):
"""Test if state is supported."""
return domain == vacuum.DOMAIN

Expand Down Expand Up @@ -484,7 +485,7 @@ class StartStopTrait(_Trait):
]

@staticmethod
def supported(domain, features):
def supported(domain, features, device_class):
"""Test if state is supported."""
return domain == vacuum.DOMAIN

Expand Down Expand Up @@ -554,7 +555,7 @@ class TemperatureSettingTrait(_Trait):
google_to_hass = {value: key for key, value in hass_to_google.items()}

@staticmethod
def supported(domain, features):
def supported(domain, features, device_class):
"""Test if state is supported."""
if domain != climate.DOMAIN:
return False
Expand Down Expand Up @@ -739,7 +740,7 @@ class LockUnlockTrait(_Trait):
]

@staticmethod
def supported(domain, features):
def supported(domain, features, device_class):
"""Test if state is supported."""
return domain == lock.DOMAIN

Expand Down Expand Up @@ -790,7 +791,7 @@ class FanSpeedTrait(_Trait):
}

@staticmethod
def supported(domain, features):
def supported(domain, features, device_class):
"""Test if state is supported."""
if domain != fan.DOMAIN:
return False
Expand Down Expand Up @@ -941,7 +942,7 @@ class ModesTrait(_Trait):
}

@staticmethod
def supported(domain, features):
def supported(domain, features, device_class):
"""Test if state is supported."""
if domain != media_player.DOMAIN:
return False
Expand Down Expand Up @@ -1042,13 +1043,25 @@ class OpenCloseTrait(_Trait):
]

@staticmethod
def supported(domain, features):
def supported(domain, features, device_class):
"""Test if state is supported."""
return domain == cover.DOMAIN
if domain == cover.DOMAIN:
return True

return domain == binary_sensor.DOMAIN and device_class in (
binary_sensor.DEVICE_CLASS_DOOR,
binary_sensor.DEVICE_CLASS_GARAGE_DOOR,
binary_sensor.DEVICE_CLASS_LOCK,
binary_sensor.DEVICE_CLASS_OPENING,
binary_sensor.DEVICE_CLASS_WINDOW,
)

def sync_attributes(self):
"""Return opening direction."""
return {}
attrs = {}
if self.state.domain == binary_sensor.DOMAIN:
attrs['queryOnlyOpenClose'] = True
return attrs

def query_attributes(self):
"""Return state query attributes."""
Expand All @@ -1073,6 +1086,12 @@ def query_attributes(self):
else:
response['openPercent'] = 0

elif domain == binary_sensor.DOMAIN:
if self.state.state == STATE_ON:
response['openPercent'] = 100
else:
response['openPercent'] = 0

return response

async def execute(self, command, data, params):
Expand Down
Loading