Advertisement
Guest User

xiaomi_aqara.py modificado

a guest
Dec 27th, 2018
1,139
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 16.38 KB | None | 0 0
  1. """Support for Xiaomi aqara binary sensors."""
  2. import logging
  3.  
  4. from homeassistant.components.binary_sensor import BinarySensorDevice
  5. from homeassistant.components.xiaomi_aqara import (PY_XIAOMI_GATEWAY,
  6. XiaomiDevice)
  7. from homeassistant.core import callback
  8. from homeassistant.helpers.event import async_call_later
  9.  
  10. _LOGGER = logging.getLogger(__name__)
  11.  
  12. NO_CLOSE = 'no_close'
  13. ATTR_OPEN_SINCE = 'Open since'
  14.  
  15. MOTION = 'motion'
  16. NO_MOTION = 'no_motion'
  17. ATTR_LAST_ACTION = 'last_action'
  18. ATTR_NO_MOTION_SINCE = 'No motion since'
  19.  
  20. DENSITY = 'density'
  21. ATTR_DENSITY = 'Density'
  22.  
  23.  
  24. def setup_platform(hass, config, add_entities, discovery_info=None):
  25. """Perform the setup for Xiaomi devices."""
  26. devices = []
  27. for (_, gateway) in hass.data[PY_XIAOMI_GATEWAY].gateways.items():
  28. for device in gateway.devices['binary_sensor']:
  29. model = device['model']
  30. if model in ['motion', 'sensor_motion', 'sensor_motion.aq2']:
  31. devices.append(XiaomiMotionSensor(device, hass, gateway))
  32. elif model in ['magnet', 'sensor_magnet', 'sensor_magnet.aq2']:
  33. devices.append(XiaomiDoorSensor(device, gateway))
  34. elif model == 'sensor_wleak.aq1':
  35. devices.append(XiaomiWaterLeakSensor(device, gateway))
  36. elif model in ['smoke', 'sensor_smoke']:
  37. devices.append(XiaomiSmokeSensor(device, gateway))
  38. elif model in ['natgas', 'sensor_natgas']:
  39. devices.append(XiaomiNatgasSensor(device, gateway))
  40. elif model in ['switch', 'sensor_switch',
  41. 'sensor_switch.aq2', 'sensor_switch.aq3',
  42. 'remote.b1acn01']:
  43. if 'proto' not in device or int(device['proto'][0:1]) == 1:
  44. data_key = 'status'
  45. else:
  46. data_key = 'button_0'
  47. devices.append(XiaomiButton(device, 'Switch', data_key,
  48. hass, gateway))
  49. elif model in ['86sw1', 'sensor_86sw1', 'sensor_86sw1.aq1',
  50. 'remote.b186acn01']:
  51. if 'proto' not in device or int(device['proto'][0:1]) == 1:
  52. data_key = 'channel_0'
  53. else:
  54. data_key = 'button_0'
  55. devices.append(XiaomiButton(device, 'Wall Switch', data_key,
  56. hass, gateway))
  57. elif model in ['86sw2', 'sensor_86sw2', 'sensor_86sw2.aq1',
  58. 'remote.b286acn01']:
  59. if 'proto' not in device or int(device['proto'][0:1]) == 1:
  60. data_key_left = 'channel_0'
  61. data_key_right = 'channel_1'
  62. else:
  63. data_key_left = 'button_0'
  64. data_key_right = 'button_1'
  65. devices.append(XiaomiButton(device, 'Wall Switch (Left)',
  66. data_key_left, hass, gateway))
  67. devices.append(XiaomiButton(device, 'Wall Switch (Right)',
  68. data_key_right, hass, gateway))
  69. devices.append(XiaomiButton(device, 'Wall Switch (Both)',
  70. 'dual_channel', hass, gateway))
  71. elif model in ['cube', 'sensor_cube', 'sensor_cube.aqgl01']:
  72. devices.append(XiaomiCube(device, hass, gateway))
  73. elif model in ['vibration', 'vibration.aq1']:
  74. devices.append(XiaomiVibration(device, 'Vibration',
  75. 'status', gateway))
  76. else:
  77. _LOGGER.warning('Unmapped Device Model %s', model)
  78.  
  79. add_entities(devices)
  80.  
  81.  
  82. class XiaomiBinarySensor(XiaomiDevice, BinarySensorDevice):
  83. """Representation of a base XiaomiBinarySensor."""
  84.  
  85. def __init__(self, device, name, xiaomi_hub, data_key, device_class):
  86. """Initialize the XiaomiSmokeSensor."""
  87. self._data_key = data_key
  88. self._device_class = device_class
  89. self._should_poll = False
  90. self._density = 0
  91. XiaomiDevice.__init__(self, device, name, xiaomi_hub)
  92.  
  93. @property
  94. def should_poll(self):
  95. """Return True if entity has to be polled for state."""
  96. return self._should_poll
  97.  
  98. @property
  99. def is_on(self):
  100. """Return true if sensor is on."""
  101. return self._state
  102.  
  103. @property
  104. def device_class(self):
  105. """Return the class of binary sensor."""
  106. return self._device_class
  107.  
  108. def update(self):
  109. """Update the sensor state."""
  110. _LOGGER.debug('Updating xiaomi sensor by polling')
  111. self._get_from_hub(self._sid)
  112.  
  113.  
  114. class XiaomiNatgasSensor(XiaomiBinarySensor):
  115. """Representation of a XiaomiNatgasSensor."""
  116.  
  117. def __init__(self, device, xiaomi_hub):
  118. """Initialize the XiaomiSmokeSensor."""
  119. self._density = None
  120. XiaomiBinarySensor.__init__(self, device, 'Natgas Sensor', xiaomi_hub,
  121. 'alarm', 'gas')
  122.  
  123. @property
  124. def device_state_attributes(self):
  125. """Return the state attributes."""
  126. attrs = {ATTR_DENSITY: self._density}
  127. attrs.update(super().device_state_attributes)
  128. return attrs
  129.  
  130. def parse_data(self, data, raw_data):
  131. """Parse data sent by gateway."""
  132. if DENSITY in data:
  133. self._density = int(data.get(DENSITY))
  134.  
  135. value = data.get(self._data_key)
  136. if value is None:
  137. return False
  138.  
  139. if value in ('1', '2'):
  140. if self._state:
  141. return False
  142. self._state = True
  143. return True
  144. if value == '0':
  145. if self._state:
  146. self._state = False
  147. return True
  148. return False
  149.  
  150.  
  151. class XiaomiMotionSensor(XiaomiBinarySensor):
  152. """Representation of a XiaomiMotionSensor."""
  153.  
  154. def __init__(self, device, hass, xiaomi_hub):
  155. """Initialize the XiaomiMotionSensor."""
  156. self._hass = hass
  157. self._no_motion_since = 0
  158. self._unsub_set_no_motion = None
  159. if 'proto' not in device or int(device['proto'][0:1]) == 1:
  160. data_key = 'status'
  161. else:
  162. data_key = 'motion_status'
  163. XiaomiBinarySensor.__init__(self, device, 'Motion Sensor', xiaomi_hub,
  164. data_key, 'motion')
  165.  
  166. @property
  167. def device_state_attributes(self):
  168. """Return the state attributes."""
  169. attrs = {ATTR_NO_MOTION_SINCE: self._no_motion_since}
  170. attrs.update(super().device_state_attributes)
  171. return attrs
  172.  
  173. @callback
  174. def _async_set_no_motion(self, now):
  175. """Set state to False."""
  176. self._unsub_set_no_motion = None
  177. self._state = False
  178. self.async_schedule_update_ha_state()
  179.  
  180. def parse_data(self, data, raw_data):
  181. """Parse data sent by gateway."""
  182. if raw_data['cmd'] == 'heartbeat':
  183. _LOGGER.debug(
  184. 'Skipping heartbeat of the motion sensor. '
  185. 'It can introduce an incorrect state because of a firmware '
  186. 'bug (https://github.com/home-assistant/home-assistant/pull/'
  187. '11631#issuecomment-357507744).')
  188. return
  189.  
  190. self._should_poll = False
  191. if NO_MOTION in data: # handle push from the hub
  192. self._no_motion_since = data[NO_MOTION]
  193. self._state = False
  194. return True
  195.  
  196. value = data.get(self._data_key)
  197. if value is None:
  198. return False
  199.  
  200. if value == MOTION:
  201. if self._data_key == 'motion_status':
  202. if self._unsub_set_no_motion:
  203. self._unsub_set_no_motion()
  204. self._unsub_set_no_motion = async_call_later(
  205. self._hass,
  206. 180,
  207. self._async_set_no_motion
  208. )
  209. else:
  210. self._should_poll = True
  211. if self.entity_id is not None:
  212. self._hass.bus.fire('xiaomi_aqara.motion', {
  213. 'entity_id': self.entity_id
  214. })
  215.  
  216. self._no_motion_since = 0
  217. if self._state:
  218. return False
  219. self._state = True
  220. return True
  221. if value == NO_MOTION:
  222. if not self._state:
  223. return False
  224. self._state = False
  225. return True
  226.  
  227.  
  228. class XiaomiDoorSensor(XiaomiBinarySensor):
  229. """Representation of a XiaomiDoorSensor."""
  230.  
  231. def __init__(self, device, xiaomi_hub):
  232. """Initialize the XiaomiDoorSensor."""
  233. self._open_since = 0
  234. if 'proto' not in device or int(device['proto'][0:1]) == 1:
  235. data_key = 'status'
  236. else:
  237. data_key = 'window_status'
  238. XiaomiBinarySensor.__init__(self, device, 'Door Window Sensor',
  239. xiaomi_hub, data_key, 'opening')
  240.  
  241. @property
  242. def device_state_attributes(self):
  243. """Return the state attributes."""
  244. attrs = {ATTR_OPEN_SINCE: self._open_since}
  245. attrs.update(super().device_state_attributes)
  246. return attrs
  247.  
  248. def parse_data(self, data, raw_data):
  249. """Parse data sent by gateway."""
  250. self._should_poll = False
  251. if NO_CLOSE in data: # handle push from the hub
  252. self._open_since = data[NO_CLOSE]
  253. return True
  254.  
  255. value = data.get(self._data_key)
  256. if value is None:
  257. return False
  258.  
  259. if value == 'open':
  260. self._should_poll = True
  261. if self._state:
  262. return False
  263. self._state = True
  264. return True
  265. if value == 'close':
  266. self._open_since = 0
  267. if self._state:
  268. self._state = False
  269. return True
  270. return False
  271.  
  272.  
  273. class XiaomiWaterLeakSensor(XiaomiBinarySensor):
  274. """Representation of a XiaomiWaterLeakSensor."""
  275.  
  276. def __init__(self, device, xiaomi_hub):
  277. """Initialize the XiaomiWaterLeakSensor."""
  278. if 'proto' not in device or int(device['proto'][0:1]) == 1:
  279. data_key = 'status'
  280. else:
  281. data_key = 'wleak_status'
  282. XiaomiBinarySensor.__init__(self, device, 'Water Leak Sensor',
  283. xiaomi_hub, data_key, 'moisture')
  284.  
  285. def parse_data(self, data, raw_data):
  286. """Parse data sent by gateway."""
  287. self._should_poll = False
  288.  
  289. value = data.get(self._data_key)
  290. if value is None:
  291. return False
  292.  
  293. if value == 'leak':
  294. self._should_poll = True
  295. if self._state:
  296. return False
  297. self._state = True
  298. return True
  299. if value == 'no_leak':
  300. if self._state:
  301. self._state = False
  302. return True
  303. return False
  304.  
  305.  
  306. class XiaomiSmokeSensor(XiaomiBinarySensor):
  307. """Representation of a XiaomiSmokeSensor."""
  308.  
  309. def __init__(self, device, xiaomi_hub):
  310. """Initialize the XiaomiSmokeSensor."""
  311. self._density = 0
  312. XiaomiBinarySensor.__init__(self, device, 'Smoke Sensor', xiaomi_hub,
  313. 'alarm', 'smoke')
  314.  
  315. @property
  316. def device_state_attributes(self):
  317. """Return the state attributes."""
  318. attrs = {ATTR_DENSITY: self._density}
  319. attrs.update(super().device_state_attributes)
  320. return attrs
  321.  
  322. def parse_data(self, data, raw_data):
  323. """Parse data sent by gateway."""
  324. if DENSITY in data:
  325. self._density = int(data.get(DENSITY))
  326. value = data.get(self._data_key)
  327. if value is None:
  328. return False
  329.  
  330. if value in ('1', '2'):
  331. if self._state:
  332. return False
  333. self._state = True
  334. return True
  335. if value == '0':
  336. if self._state:
  337. self._state = False
  338. return True
  339. return False
  340.  
  341.  
  342. class XiaomiVibration(XiaomiBinarySensor):
  343. """Representation of a Xiaomi Vibration Sensor."""
  344.  
  345. def __init__(self, device, name, data_key, xiaomi_hub):
  346. """Initialize the XiaomiVibration."""
  347. self._last_action = None
  348. super().__init__(device, name, xiaomi_hub, data_key, None)
  349.  
  350. @property
  351. def device_state_attributes(self):
  352. """Return the state attributes."""
  353. attrs = {ATTR_LAST_ACTION: self._last_action}
  354. attrs.update(super().device_state_attributes)
  355. return attrs
  356.  
  357. def parse_data(self, data, raw_data):
  358. """Parse data sent by gateway."""
  359. value = data.get(self._data_key)
  360. if value is None:
  361. return False
  362.  
  363. if value not in ('vibrate', 'tilt', 'free_fall'):
  364. _LOGGER.warning("Unsupported movement_type detected: %s",
  365. value)
  366. return False
  367.  
  368. self.hass.bus.fire('xiaomi_aqara.movement', {
  369. 'entity_id': self.entity_id,
  370. 'movement_type': value
  371. })
  372. self._last_action = value
  373.  
  374. return True
  375.  
  376.  
  377. class XiaomiButton(XiaomiBinarySensor):
  378. """Representation of a Xiaomi Button."""
  379.  
  380. def __init__(self, device, name, data_key, hass, xiaomi_hub):
  381. """Initialize the XiaomiButton."""
  382. self._hass = hass
  383. self._last_action = None
  384. XiaomiBinarySensor.__init__(self, device, name, xiaomi_hub,
  385. data_key, None)
  386.  
  387. @property
  388. def device_state_attributes(self):
  389. """Return the state attributes."""
  390. attrs = {ATTR_LAST_ACTION: self._last_action}
  391. attrs.update(super().device_state_attributes)
  392. return attrs
  393.  
  394. def parse_data(self, data, raw_data):
  395. """Parse data sent by gateway."""
  396. value = data.get(self._data_key)
  397. if value is None:
  398. return False
  399.  
  400. if value == 'long_click_press':
  401. self._state = True
  402. click_type = 'long_click_press'
  403. elif value == 'long_click_release':
  404. self._state = False
  405. click_type = 'hold'
  406. elif value == 'click':
  407. click_type = 'single'
  408. elif value == 'double_click':
  409. click_type = 'double'
  410. elif value == 'both_click':
  411. click_type = 'both'
  412. elif value == 'shake':
  413. click_type = 'shake'
  414. elif value in ['long_click', 'long_both_click']:
  415. return False
  416. else:
  417. _LOGGER.warning("Unsupported click_type detected: %s", value)
  418. return False
  419.  
  420. self._hass.bus.fire('xiaomi_aqara.click', {
  421. 'entity_id': self.entity_id,
  422. 'click_type': click_type
  423. })
  424. self._last_action = click_type
  425.  
  426. return True
  427.  
  428.  
  429. class XiaomiCube(XiaomiBinarySensor):
  430. """Representation of a Xiaomi Cube."""
  431.  
  432. def __init__(self, device, hass, xiaomi_hub):
  433. """Initialize the Xiaomi Cube."""
  434. self._hass = hass
  435. self._last_action = None
  436. self._state = False
  437. if 'proto' not in device or int(device['proto'][0:1]) == 1:
  438. data_key = 'status'
  439. else:
  440. data_key = 'cube_status'
  441. XiaomiBinarySensor.__init__(self, device, 'Cube', xiaomi_hub,
  442. data_key, None)
  443.  
  444. @property
  445. def device_state_attributes(self):
  446. """Return the state attributes."""
  447. attrs = {ATTR_LAST_ACTION: self._last_action}
  448. attrs.update(super().device_state_attributes)
  449. return attrs
  450.  
  451. def parse_data(self, data, raw_data):
  452. """Parse data sent by gateway."""
  453. if self._data_key in data:
  454. self._hass.bus.fire('xiaomi_aqara.cube_action', {
  455. 'entity_id': self.entity_id,
  456. 'action_type': data[self._data_key]
  457. })
  458. self._last_action = data[self._data_key]
  459.  
  460. if 'rotate' in data:
  461. self._hass.bus.fire('xiaomi_aqara.cube_action', {
  462. 'entity_id': self.entity_id,
  463. 'action_type': 'rotate',
  464. 'action_value': float(data['rotate'].replace(",", "."))
  465. })
  466. self._last_action = 'rotate'
  467.  
  468. return True
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement