Skip to content

Commit

Permalink
Merge branch 'release/0.0.29'
Browse files Browse the repository at this point in the history
  • Loading branch information
dmulcahey committed Dec 26, 2019
2 parents f4b071e + 4551bef commit f58654e
Show file tree
Hide file tree
Showing 50 changed files with 1,429 additions and 238 deletions.
18 changes: 18 additions & 0 deletions Contributors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Contributors
- [David F. Mulcahey] (https://github.com/dmulcahey)
- [roblandry] (https://github.com/roblandry)
- [presslab-us] (https://github.com/presslab-us)
- [Alexei Chetroi] (https://github.com/Adminiuga)
- [Abílio Costa] (https://github.com/abmantis)
- [Andreas Setterlind] (https://github.com/Gamester17)
- [prairiesnpr] (https://github.com/prairiesnpr)
- [Daniel Lashua] (https://github.com/dlashua)
- [bballwiz5] (https://github.com/bballwiz5)
- [Ross Patterson] (https://github.com/rpatterson)
- [Marc Egli] (https://github.com/frog32)
- [Dinko Bajric] (https://github.com/dbajric)
- [brg468] (https://github.com/brg468)
- [James Riley] (https://github.com/Thalagyrt)
- [Shulyaka] (https://github.com/Shulyaka)
- [Nemesis24] (https://github.com/Nemesis24)
- [Andy Zickler](https://github.com/andyzickler)
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,14 @@ ZHA device handlers bridge the functionality gap created when manufacturers devi

Custom quirks implementations for zigpy implemented as ZHA Device Handlers are a similar concept to that of [Hub-connected Device Handlers for the SmartThings Classics platform](https://docs.smartthings.com/en/latest/device-type-developers-guide/) as well that of [Zigbee-Shepherd Converters as used by Zigbee2mqtt](https://www.zigbee2mqtt.io/how_tos/how_to_support_new_devices.html), meaning they are virtual representation of a physical device that expose additional functionality that is not provided out-of-the-box by the existing integration between these platforms. See [Device Specifics](#Device-Specifics) for details.

# Contributing
[guidelines](./CONTRIBUTING.md)
# How to contribute

For specific Zigbee debugging instructions on capturing logs and more, see the contributing guidelines in the CONTRIBUTING.md file:
- [Guidelines in CONTRIBUTING.md](./CONTRIBUTING.md)

If you are looking to make your first code contribution to this project then we also suggest that you follow the steps in these guides:
- https://github.com/firstcontributions/first-contributions/blob/master/README.md
- https://github.com/firstcontributions/first-contributions/blob/master/github-desktop-tutorial.md

# Currently Supported Devices:

Expand Down Expand Up @@ -109,6 +115,7 @@ Custom quirks implementations for zigpy implemented as ZHA Device Handlers are a

- Some functionality requires a coordinator device to be XBee as well
- GPIO pins are exposed to Home Assistant as switches
- Analog inputs are exposed as sensors
- Outgoing UART data can be sent with `zha.issue_zigbee_cluster_command` service
- Incoming UART data will generate `zha_event` event.

Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from setuptools import find_packages, setup

VERSION = "0.0.28"
VERSION = "0.0.29"


def readme():
Expand Down
48 changes: 48 additions & 0 deletions tests/test_kof.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"""Tests for KOF."""
from unittest import mock

import zigpy.device
import zigpy.endpoint
import zigpy.quirks


def test_kof_no_reply():
"""Test KOF No reply."""

class TestCluster(zigpy.quirks.kof.NoReplyMixin, zigpy.quirks.CustomCluster):
"""Test Cluster Class."""

cluster_id = 0x1234
void_input_commands = [0x0002]
server_commands = {
0x0001: ("noop", (), False),
0x0002: ("noop_noreply", (), False),
}
client_commands = {}

end_point = mock.MagicMock()
cluster = TestCluster(end_point)

cluster.command(0x0001)
end_point.request.assert_called_with(
mock.ANY, mock.ANY, mock.ANY, expect_reply=True, command_id=mock.ANY
)
end_point.reset_mock()

cluster.command(0x0001, expect_reply=False)
end_point.request.assert_called_with(
mock.ANY, mock.ANY, mock.ANY, expect_reply=False, command_id=mock.ANY
)
end_point.reset_mock()

cluster.command(0x0002)
end_point.request.assert_called_with(
mock.ANY, mock.ANY, mock.ANY, expect_reply=False, command_id=mock.ANY
)
end_point.reset_mock()

cluster.command(0x0002, expect_reply=True)
end_point.request.assert_called_with(
mock.ANY, mock.ANY, mock.ANY, expect_reply=True, command_id=mock.ANY
)
end_point.reset_mock()
29 changes: 21 additions & 8 deletions zhaquirks/__init__.py
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Quirks implementations for the ZHA component of Homeassistant."""
import logging
import importlib
import pkgutil

Expand All @@ -17,6 +18,8 @@
ZHA_SEND_EVENT,
)

_LOGGER = logging.getLogger(__name__)


class Bus(ListenableMixin):
"""Event bus implementation."""
Expand Down Expand Up @@ -116,8 +119,8 @@ class PowerConfigurationCluster(CustomCluster, PowerConfiguration):
cluster_id = PowerConfiguration.cluster_id
BATTERY_VOLTAGE_ATTR = 0x0020
BATTERY_PERCENTAGE_REMAINING = 0x0021
MIN_VOLTS = 2.1
MAX_VOLTS = 3.2
MIN_VOLTS = 1.5 # old 2.1
MAX_VOLTS = 2.8 # old 3.2

def _update_attribute(self, attrid, value):
super()._update_attribute(attrid, value)
Expand All @@ -131,14 +134,24 @@ def _calculate_battery_percentage(self, raw_value):
if raw_value in (0, 255):
return -1
volts = raw_value / 10
if volts < self.MIN_VOLTS:
volts = self.MIN_VOLTS
elif volts > self.MAX_VOLTS:
volts = self.MAX_VOLTS
volts = max(volts, self.MIN_VOLTS)
volts = min(volts, self.MAX_VOLTS)

percent = round(
((volts - self.MIN_VOLTS) / (self.MAX_VOLTS - self.MIN_VOLTS)) * 200
)

percent = ((volts - self.MIN_VOLTS) / (self.MAX_VOLTS - self.MIN_VOLTS)) * 200
_LOGGER.debug(
"%s %s, Voltage [RAW]:%s [Max]:%s [Min]:%s, Battery Percent: %s",
self.endpoint.device.manufacturer,
self.endpoint.device.model,
raw_value,
self.MAX_VOLTS,
self.MIN_VOLTS,
percent / 2,
)

return round(min(200, percent), 2)
return percent


NAME = __name__
Expand Down
15 changes: 12 additions & 3 deletions zhaquirks/centralite/3130.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
)
from zigpy.zcl.clusters.measurement import TemperatureMeasurement

from zhaquirks.centralite import CENTRALITE, PowerConfigurationCluster
from zhaquirks import PowerConfigurationCluster
from zhaquirks.centralite import CENTRALITE
from zhaquirks.const import (
COMMAND,
COMMAND_MOVE,
Expand All @@ -35,6 +36,14 @@
DIAGNOSTICS_CLUSTER_ID = 0x0B05 # decimal = 2821


class CustomPowerConfigurationCluster(PowerConfigurationCluster):
"""Custom PowerConfigurationCluster."""

cluster_id = PowerConfigurationCluster.cluster_id
MIN_VOLTS = 2.1
MAX_VOLTS = 3.0


class CentraLite3130(CustomDevice):
"""Custom device representing centralite 3130."""

Expand All @@ -50,7 +59,7 @@ class CentraLite3130(CustomDevice):
DEVICE_TYPE: zha.DeviceType.LEVEL_CONTROL_SWITCH,
INPUT_CLUSTERS: [
Basic.cluster_id,
PowerConfigurationCluster.cluster_id,
CustomPowerConfigurationCluster.cluster_id,
Identify.cluster_id,
PollControl.cluster_id,
TemperatureMeasurement.cluster_id,
Expand All @@ -70,7 +79,7 @@ class CentraLite3130(CustomDevice):
1: {
INPUT_CLUSTERS: [
Basic.cluster_id,
PowerConfigurationCluster,
CustomPowerConfigurationCluster,
Identify.cluster_id,
PollControl.cluster_id,
DIAGNOSTICS_CLUSTER_ID,
Expand Down
3 changes: 2 additions & 1 deletion zhaquirks/centralite/3157100.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
from zigpy.zcl.clusters.general import Basic, Identify, Ota, PollControl, Time
from zigpy.zcl.clusters.hvac import Fan, Thermostat, UserInterface

from zhaquirks.centralite import CENTRALITE, PowerConfigurationCluster
from zhaquirks import PowerConfigurationCluster
from zhaquirks.centralite import CENTRALITE
from zhaquirks.const import (
DEVICE_TYPE,
ENDPOINTS,
Expand Down
3 changes: 2 additions & 1 deletion zhaquirks/centralite/3300S.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
from zigpy.zcl.clusters.measurement import TemperatureMeasurement
from zigpy.zcl.clusters.security import IasZone

from zhaquirks.centralite import CENTRALITE, PowerConfigurationCluster
from zhaquirks import PowerConfigurationCluster
from zhaquirks.centralite import CENTRALITE
from zhaquirks.const import (
DEVICE_TYPE,
ENDPOINTS,
Expand Down
3 changes: 2 additions & 1 deletion zhaquirks/centralite/3305S.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
from zigpy.zcl.clusters.measurement import OccupancySensing, TemperatureMeasurement
from zigpy.zcl.clusters.security import IasZone

from zhaquirks.centralite import CENTRALITE, PowerConfigurationCluster
from zhaquirks import PowerConfigurationCluster
from zhaquirks.centralite import CENTRALITE
from zhaquirks.const import (
DEVICE_TYPE,
ENDPOINTS,
Expand Down
27 changes: 17 additions & 10 deletions zhaquirks/centralite/3310S.py
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
"""Centralite 3310S implementation."""
from zigpy import quirks
from zigpy.profiles import zha
from zigpy.quirks import CustomDevice
from zigpy.quirks.smartthings import (
SmartthingsRelativeHumidityCluster,
SmartthingsTemperatureHumiditySensor,
)
from zigpy.quirks import CustomDevice, CustomCluster
from zigpy.zcl.clusters.general import Basic, Identify, Ota, PollControl
from zigpy.zcl.clusters.measurement import TemperatureMeasurement
import zigpy.types as t

from zhaquirks.centralite import CENTRALITE, PowerConfigurationCluster
from zhaquirks import PowerConfigurationCluster
from zhaquirks.centralite import CENTRALITE
from zhaquirks.const import (
DEVICE_TYPE,
ENDPOINTS,
Expand All @@ -20,11 +17,21 @@
)

DIAGNOSTICS_CLUSTER_ID = 0x0B05 # decimal = 2821
SMRT_THINGS_REL_HUM_CLSTR = 0xFC45


class SmartthingsRelativeHumidityCluster(CustomCluster):
"""Smart Things Relative Humidity Cluster."""

# remove the zigpy version of this device handler
if SmartthingsTemperatureHumiditySensor in quirks._DEVICE_REGISTRY:
quirks._DEVICE_REGISTRY.remove(SmartthingsTemperatureHumiditySensor)
cluster_id = SMRT_THINGS_REL_HUM_CLSTR
name = "Smartthings Relative Humidity Measurement"
ep_attribute = "humidity"
attributes = {
# Relative Humidity Measurement Information
0x0000: ("measured_value", t.int16s)
}
server_commands = {}
client_commands = {}


class CentraLite3310S(CustomDevice):
Expand Down
7 changes: 2 additions & 5 deletions zhaquirks/centralite/3321S.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,8 @@
from zigpy.zcl.clusters.measurement import TemperatureMeasurement
from zigpy.zcl.clusters.security import IasZone

from zhaquirks.centralite import (
CENTRALITE,
CentraLiteAccelCluster,
PowerConfigurationCluster,
)
from zhaquirks import PowerConfigurationCluster
from zhaquirks.centralite import CENTRALITE, CentraLiteAccelCluster
from zhaquirks.const import (
DEVICE_TYPE,
ENDPOINTS,
Expand Down
15 changes: 12 additions & 3 deletions zhaquirks/centralite/3460L.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
)
from zigpy.zcl.clusters.measurement import TemperatureMeasurement

from zhaquirks.centralite import CENTRALITE, PowerConfigurationCluster
from zhaquirks import PowerConfigurationCluster
from zhaquirks.centralite import CENTRALITE
from zhaquirks.const import (
DEVICE_TYPE,
ENDPOINTS,
Expand All @@ -25,6 +26,14 @@
DIAGNOSTICS_CLUSTER_ID = 0x0B05 # decimal = 2821


class CustomPowerConfigurationCluster(PowerConfigurationCluster):
"""Custom PowerConfigurationCluster."""

cluster_id = PowerConfigurationCluster.cluster_id
MIN_VOLTS = 2.1
MAX_VOLTS = 3.0


class CentraLite3460L(CustomDevice):
"""Custom device representing centralite 3460L."""

Expand All @@ -40,7 +49,7 @@ class CentraLite3460L(CustomDevice):
DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL,
INPUT_CLUSTERS: [
Basic.cluster_id,
PowerConfigurationCluster.cluster_id,
CustomPowerConfigurationCluster.cluster_id,
Identify.cluster_id,
OnOffConfiguration.cluster_id,
PollControl.cluster_id,
Expand All @@ -61,7 +70,7 @@ class CentraLite3460L(CustomDevice):
1: {
INPUT_CLUSTERS: [
Basic.cluster_id,
PowerConfigurationCluster,
CustomPowerConfigurationCluster,
Identify.cluster_id,
OnOffConfiguration.cluster_id,
PollControl.cluster_id,
Expand Down
44 changes: 0 additions & 44 deletions zhaquirks/centralite/__init__.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -3,55 +3,11 @@

from zigpy.quirks import CustomCluster
import zigpy.types as t
from zigpy.zcl.clusters.general import PowerConfiguration

_LOGGER = logging.getLogger(__name__)
CENTRALITE = "CentraLite"


class PowerConfigurationCluster(CustomCluster, PowerConfiguration):
"""Centralite power configuration cluster."""

cluster_id = PowerConfiguration.cluster_id
BATTERY_VOLTAGE_ATTR = 0x0020
BATTERY_PERCENTAGE_REMAINING = 0x0021
MIN_VOLTS = 21
MAX_VOLTS = 31
VOLTS_TO_PERCENT = {
31: 100,
30: 90,
29: 80,
28: 70,
27: 60,
26: 50,
25: 40,
24: 30,
23: 20,
22: 10,
21: 0,
}

def _update_attribute(self, attrid, value):
super()._update_attribute(attrid, value)
if attrid == self.BATTERY_VOLTAGE_ATTR:
super()._update_attribute(
self.BATTERY_PERCENTAGE_REMAINING,
self._calculate_battery_percentage(value),
)

def _calculate_battery_percentage(self, raw_value):
volts = raw_value
if raw_value < self.MIN_VOLTS:
volts = self.MIN_VOLTS
elif raw_value > self.MAX_VOLTS:
volts = self.MAX_VOLTS

percent = self.VOLTS_TO_PERCENT.get(volts, -1)
if percent != -1:
percent = percent * 2
return percent


class CentraLiteAccelCluster(CustomCluster):
"""Centralite acceleration cluster."""

Expand Down
3 changes: 2 additions & 1 deletion zhaquirks/centralite/ias.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
from zigpy.zcl.clusters.measurement import TemperatureMeasurement
from zigpy.zcl.clusters.security import IasZone

from . import CENTRALITE, PowerConfigurationCluster
from zhaquirks import PowerConfigurationCluster
from . import CENTRALITE
from ..const import (
DEVICE_TYPE,
ENDPOINTS,
Expand Down
Loading

0 comments on commit f58654e

Please sign in to comment.