Support for renaming ZWave values (#7780)
* Support for renaming ZWave values * Improve test
This commit is contained in:
parent
6d41024e76
commit
9c9f5068b7
6 changed files with 122 additions and 7 deletions
|
@ -30,7 +30,7 @@ from homeassistant.components.frontend import register_built_in_panel
|
||||||
|
|
||||||
from . import api
|
from . import api
|
||||||
from . import const
|
from . import const
|
||||||
from .const import DOMAIN, DATA_DEVICES, DATA_NETWORK
|
from .const import DOMAIN, DATA_DEVICES, DATA_NETWORK, DATA_ENTITY_VALUES
|
||||||
from .node_entity import ZWaveBaseEntity, ZWaveNodeEntity
|
from .node_entity import ZWaveBaseEntity, ZWaveNodeEntity
|
||||||
from . import workaround
|
from . import workaround
|
||||||
from .discovery_schemas import DISCOVERY_SCHEMAS
|
from .discovery_schemas import DISCOVERY_SCHEMAS
|
||||||
|
@ -74,12 +74,20 @@ RENAME_NODE_SCHEMA = vol.Schema({
|
||||||
vol.Required(const.ATTR_NODE_ID): vol.Coerce(int),
|
vol.Required(const.ATTR_NODE_ID): vol.Coerce(int),
|
||||||
vol.Required(const.ATTR_NAME): cv.string,
|
vol.Required(const.ATTR_NAME): cv.string,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
RENAME_VALUE_SCHEMA = vol.Schema({
|
||||||
|
vol.Required(const.ATTR_NODE_ID): vol.Coerce(int),
|
||||||
|
vol.Required(const.ATTR_VALUE_ID): vol.Coerce(int),
|
||||||
|
vol.Required(const.ATTR_NAME): cv.string,
|
||||||
|
})
|
||||||
|
|
||||||
SET_CONFIG_PARAMETER_SCHEMA = vol.Schema({
|
SET_CONFIG_PARAMETER_SCHEMA = vol.Schema({
|
||||||
vol.Required(const.ATTR_NODE_ID): vol.Coerce(int),
|
vol.Required(const.ATTR_NODE_ID): vol.Coerce(int),
|
||||||
vol.Required(const.ATTR_CONFIG_PARAMETER): vol.Coerce(int),
|
vol.Required(const.ATTR_CONFIG_PARAMETER): vol.Coerce(int),
|
||||||
vol.Required(const.ATTR_CONFIG_VALUE): vol.Any(vol.Coerce(int), cv.string),
|
vol.Required(const.ATTR_CONFIG_VALUE): vol.Any(vol.Coerce(int), cv.string),
|
||||||
vol.Optional(const.ATTR_CONFIG_SIZE, default=2): vol.Coerce(int)
|
vol.Optional(const.ATTR_CONFIG_SIZE, default=2): vol.Coerce(int)
|
||||||
})
|
})
|
||||||
|
|
||||||
PRINT_CONFIG_PARAMETER_SCHEMA = vol.Schema({
|
PRINT_CONFIG_PARAMETER_SCHEMA = vol.Schema({
|
||||||
vol.Required(const.ATTR_NODE_ID): vol.Coerce(int),
|
vol.Required(const.ATTR_NODE_ID): vol.Coerce(int),
|
||||||
vol.Required(const.ATTR_CONFIG_PARAMETER): vol.Coerce(int),
|
vol.Required(const.ATTR_CONFIG_PARAMETER): vol.Coerce(int),
|
||||||
|
@ -258,6 +266,7 @@ def setup(hass, config):
|
||||||
|
|
||||||
network = hass.data[DATA_NETWORK] = ZWaveNetwork(options, autostart=False)
|
network = hass.data[DATA_NETWORK] = ZWaveNetwork(options, autostart=False)
|
||||||
hass.data[DATA_DEVICES] = {}
|
hass.data[DATA_DEVICES] = {}
|
||||||
|
hass.data[DATA_ENTITY_VALUES] = []
|
||||||
|
|
||||||
if use_debug: # pragma: no cover
|
if use_debug: # pragma: no cover
|
||||||
def log_all(signal, value=None):
|
def log_all(signal, value=None):
|
||||||
|
@ -276,12 +285,10 @@ def setup(hass, config):
|
||||||
|
|
||||||
dispatcher.connect(log_all, weak=False)
|
dispatcher.connect(log_all, weak=False)
|
||||||
|
|
||||||
discovered_values = []
|
|
||||||
|
|
||||||
def value_added(node, value):
|
def value_added(node, value):
|
||||||
"""Handle new added value to a node on the network."""
|
"""Handle new added value to a node on the network."""
|
||||||
# Check if this value should be tracked by an existing entity
|
# Check if this value should be tracked by an existing entity
|
||||||
for values in discovered_values:
|
for values in hass.data[DATA_ENTITY_VALUES]:
|
||||||
values.check_value(value)
|
values.check_value(value)
|
||||||
|
|
||||||
for schema in DISCOVERY_SCHEMAS:
|
for schema in DISCOVERY_SCHEMAS:
|
||||||
|
@ -294,7 +301,11 @@ def setup(hass, config):
|
||||||
|
|
||||||
values = ZWaveDeviceEntityValues(
|
values = ZWaveDeviceEntityValues(
|
||||||
hass, schema, value, config, device_config)
|
hass, schema, value, config, device_config)
|
||||||
discovered_values.append(values)
|
|
||||||
|
# We create a new list and update the reference here so that
|
||||||
|
# the list can be safely iterated over in the main thread
|
||||||
|
new_values = hass.data[DATA_ENTITY_VALUES] + [values]
|
||||||
|
hass.data[DATA_ENTITY_VALUES] = new_values
|
||||||
|
|
||||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||||
|
|
||||||
|
@ -401,6 +412,18 @@ def setup(hass, config):
|
||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
"Renamed Z-Wave node %d to %s", node_id, name)
|
"Renamed Z-Wave node %d to %s", node_id, name)
|
||||||
|
|
||||||
|
def rename_value(service):
|
||||||
|
"""Rename a node value."""
|
||||||
|
node_id = service.data.get(const.ATTR_NODE_ID)
|
||||||
|
value_id = service.data.get(const.ATTR_VALUE_ID)
|
||||||
|
node = network.nodes[node_id]
|
||||||
|
value = node.values[value_id]
|
||||||
|
name = service.data.get(const.ATTR_NAME)
|
||||||
|
value.label = name
|
||||||
|
_LOGGER.info(
|
||||||
|
"Renamed Z-Wave value (Node %d Value %d) to %s",
|
||||||
|
node_id, value_id, name)
|
||||||
|
|
||||||
def remove_failed_node(service):
|
def remove_failed_node(service):
|
||||||
"""Remove failed node."""
|
"""Remove failed node."""
|
||||||
node_id = service.data.get(const.ATTR_NODE_ID)
|
node_id = service.data.get(const.ATTR_NODE_ID)
|
||||||
|
@ -585,6 +608,10 @@ def setup(hass, config):
|
||||||
hass.services.register(DOMAIN, const.SERVICE_RENAME_NODE, rename_node,
|
hass.services.register(DOMAIN, const.SERVICE_RENAME_NODE, rename_node,
|
||||||
descriptions[const.SERVICE_RENAME_NODE],
|
descriptions[const.SERVICE_RENAME_NODE],
|
||||||
schema=RENAME_NODE_SCHEMA)
|
schema=RENAME_NODE_SCHEMA)
|
||||||
|
hass.services.register(DOMAIN, const.SERVICE_RENAME_VALUE,
|
||||||
|
rename_value,
|
||||||
|
descriptions[const.SERVICE_RENAME_VALUE],
|
||||||
|
schema=RENAME_VALUE_SCHEMA)
|
||||||
hass.services.register(DOMAIN, const.SERVICE_SET_CONFIG_PARAMETER,
|
hass.services.register(DOMAIN, const.SERVICE_SET_CONFIG_PARAMETER,
|
||||||
set_config_parameter,
|
set_config_parameter,
|
||||||
descriptions[
|
descriptions[
|
||||||
|
@ -644,6 +671,7 @@ def setup(hass, config):
|
||||||
|
|
||||||
if 'frontend' in hass.config.components:
|
if 'frontend' in hass.config.components:
|
||||||
register_built_in_panel(hass, 'zwave', 'Z-Wave', 'mdi:nfc')
|
register_built_in_panel(hass, 'zwave', 'Z-Wave', 'mdi:nfc')
|
||||||
|
hass.http.register_view(api.ZWaveNodeValueView)
|
||||||
hass.http.register_view(api.ZWaveNodeGroupView)
|
hass.http.register_view(api.ZWaveNodeGroupView)
|
||||||
hass.http.register_view(api.ZWaveNodeConfigView)
|
hass.http.register_view(api.ZWaveNodeConfigView)
|
||||||
hass.http.register_view(api.ZWaveUserCodeView)
|
hass.http.register_view(api.ZWaveUserCodeView)
|
||||||
|
|
|
@ -9,6 +9,32 @@ from . import const
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class ZWaveNodeValueView(HomeAssistantView):
|
||||||
|
"""View to return the node values."""
|
||||||
|
|
||||||
|
url = r"/api/zwave/values/{node_id:\d+}"
|
||||||
|
name = "api:zwave:values"
|
||||||
|
|
||||||
|
@ha.callback
|
||||||
|
def get(self, request, node_id):
|
||||||
|
"""Retrieve groups of node."""
|
||||||
|
nodeid = int(node_id)
|
||||||
|
hass = request.app['hass']
|
||||||
|
values_list = hass.data[const.DATA_ENTITY_VALUES]
|
||||||
|
|
||||||
|
values_data = {}
|
||||||
|
# Return a list of values for this node that are used as a
|
||||||
|
# primary value for an entity
|
||||||
|
for entity_values in values_list:
|
||||||
|
if entity_values.primary.node.node_id != nodeid:
|
||||||
|
continue
|
||||||
|
|
||||||
|
values_data[entity_values.primary.value_id] = {
|
||||||
|
'label': entity_values.primary.label,
|
||||||
|
}
|
||||||
|
return self.json(values_data)
|
||||||
|
|
||||||
|
|
||||||
class ZWaveNodeGroupView(HomeAssistantView):
|
class ZWaveNodeGroupView(HomeAssistantView):
|
||||||
"""View to return the nodes group configuration."""
|
"""View to return the nodes group configuration."""
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ DISCOVERY_DEVICE = 'device'
|
||||||
|
|
||||||
DATA_DEVICES = 'zwave_devices'
|
DATA_DEVICES = 'zwave_devices'
|
||||||
DATA_NETWORK = 'zwave_network'
|
DATA_NETWORK = 'zwave_network'
|
||||||
|
DATA_ENTITY_VALUES = 'zwave_entity_values'
|
||||||
|
|
||||||
SERVICE_CHANGE_ASSOCIATION = "change_association"
|
SERVICE_CHANGE_ASSOCIATION = "change_association"
|
||||||
SERVICE_ADD_NODE = "add_node"
|
SERVICE_ADD_NODE = "add_node"
|
||||||
|
@ -38,6 +39,7 @@ SERVICE_SET_WAKEUP = "set_wakeup"
|
||||||
SERVICE_STOP_NETWORK = "stop_network"
|
SERVICE_STOP_NETWORK = "stop_network"
|
||||||
SERVICE_START_NETWORK = "start_network"
|
SERVICE_START_NETWORK = "start_network"
|
||||||
SERVICE_RENAME_NODE = "rename_node"
|
SERVICE_RENAME_NODE = "rename_node"
|
||||||
|
SERVICE_RENAME_VALUE = "rename_value"
|
||||||
SERVICE_REFRESH_ENTITY = "refresh_entity"
|
SERVICE_REFRESH_ENTITY = "refresh_entity"
|
||||||
SERVICE_REFRESH_NODE = "refresh_node"
|
SERVICE_REFRESH_NODE = "refresh_node"
|
||||||
SERVICE_RESET_NODE_METERS = "reset_node_meters"
|
SERVICE_RESET_NODE_METERS = "reset_node_meters"
|
||||||
|
|
|
@ -109,6 +109,19 @@ rename_node:
|
||||||
description: New Name
|
description: New Name
|
||||||
example: 'kitchen'
|
example: 'kitchen'
|
||||||
|
|
||||||
|
rename_value:
|
||||||
|
description: Set the name of a node value. Value IDs can be queried from /api/zwave/values/{node_id}
|
||||||
|
fields:
|
||||||
|
node_id:
|
||||||
|
description: ID of the node to rename.
|
||||||
|
example: 10
|
||||||
|
value_id:
|
||||||
|
description: ID of the value to rename.
|
||||||
|
example: 72037594255792737
|
||||||
|
name:
|
||||||
|
description: New Name
|
||||||
|
example: 'Luminosity'
|
||||||
|
|
||||||
reset_node_meters:
|
reset_node_meters:
|
||||||
description: Resets the meter counters of a node.
|
description: Resets the meter counters of a node.
|
||||||
fields:
|
fields:
|
||||||
|
|
|
@ -3,9 +3,38 @@ import asyncio
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
from homeassistant.components.zwave import DATA_NETWORK, const
|
from homeassistant.components.zwave import DATA_NETWORK, const
|
||||||
from homeassistant.components.zwave.api import (
|
from homeassistant.components.zwave.api import (
|
||||||
ZWaveNodeGroupView, ZWaveNodeConfigView, ZWaveUserCodeView)
|
ZWaveNodeValueView, ZWaveNodeGroupView, ZWaveNodeConfigView,
|
||||||
|
ZWaveUserCodeView)
|
||||||
from tests.common import mock_http_component_app
|
from tests.common import mock_http_component_app
|
||||||
from tests.mock.zwave import MockNode, MockValue
|
from tests.mock.zwave import MockNode, MockValue, MockEntityValues
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_get_values(hass, test_client):
|
||||||
|
"""Test getting values on node."""
|
||||||
|
app = mock_http_component_app(hass)
|
||||||
|
ZWaveNodeValueView().register(app.router)
|
||||||
|
|
||||||
|
node = MockNode(node_id=1)
|
||||||
|
value = MockValue(value_id=123456, node=node, label='Test Label')
|
||||||
|
values = MockEntityValues(primary=value)
|
||||||
|
node2 = MockNode(node_id=2)
|
||||||
|
value2 = MockValue(value_id=234567, node=node2, label='Test Label 2')
|
||||||
|
values2 = MockEntityValues(primary=value2)
|
||||||
|
hass.data[const.DATA_ENTITY_VALUES] = [values, values2]
|
||||||
|
|
||||||
|
client = yield from test_client(app)
|
||||||
|
|
||||||
|
resp = yield from client.get('/api/zwave/values/1')
|
||||||
|
|
||||||
|
assert resp.status == 200
|
||||||
|
result = yield from resp.json()
|
||||||
|
|
||||||
|
assert result == {
|
||||||
|
'123456': {
|
||||||
|
'label': 'Test Label',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
|
|
|
@ -868,6 +868,23 @@ class TestZWaveServices(unittest.TestCase):
|
||||||
|
|
||||||
assert self.zwave_network.nodes[11].name == 'test_name'
|
assert self.zwave_network.nodes[11].name == 'test_name'
|
||||||
|
|
||||||
|
def test_rename_value(self):
|
||||||
|
"""Test zwave rename_value service."""
|
||||||
|
node = MockNode(node_id=14)
|
||||||
|
value = MockValue(index=12, value_id=123456, label="Old Label")
|
||||||
|
node.values = {123456: value}
|
||||||
|
self.zwave_network.nodes = {11: node}
|
||||||
|
|
||||||
|
assert value.label == "Old Label"
|
||||||
|
self.hass.services.call('zwave', 'rename_value', {
|
||||||
|
const.ATTR_NODE_ID: 11,
|
||||||
|
const.ATTR_VALUE_ID: 123456,
|
||||||
|
const.ATTR_NAME: "New Label",
|
||||||
|
})
|
||||||
|
self.hass.block_till_done()
|
||||||
|
|
||||||
|
assert value.label == "New Label"
|
||||||
|
|
||||||
def test_remove_failed_node(self):
|
def test_remove_failed_node(self):
|
||||||
"""Test zwave remove_failed_node service."""
|
"""Test zwave remove_failed_node service."""
|
||||||
self.hass.services.call('zwave', 'remove_failed_node', {
|
self.hass.services.call('zwave', 'remove_failed_node', {
|
||||||
|
|
Loading…
Add table
Reference in a new issue