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
22 changes: 11 additions & 11 deletions homeassistant/components/zwave_js/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,24 +49,24 @@
ATTR_ZWAVE_VALUE = "zwave_value"

# service constants
ATTR_NODES = "nodes"

SERVICE_SET_VALUE = "set_value"
SERVICE_RESET_METER = "reset_meter"
SERVICE_MULTICAST_SET_VALUE = "multicast_set_value"
SERVICE_PING = "ping"
SERVICE_REFRESH_VALUE = "refresh_value"
SERVICE_SET_CONFIG_PARAMETER = "set_config_parameter"
SERVICE_BULK_SET_PARTIAL_CONFIG_PARAMETERS = "bulk_set_partial_config_parameters"

ATTR_NODES = "nodes"
# config parameter
ATTR_CONFIG_PARAMETER = "parameter"
ATTR_CONFIG_PARAMETER_BITMASK = "bitmask"
ATTR_CONFIG_VALUE = "value"

SERVICE_REFRESH_VALUE = "refresh_value"

# refresh value
ATTR_REFRESH_ALL_VALUES = "refresh_all_values"

SERVICE_SET_VALUE = "set_value"
SERVICE_MULTICAST_SET_VALUE = "multicast_set_value"

# multicast
ATTR_BROADCAST = "broadcast"

SERVICE_PING = "ping"
# meter reset
ATTR_METER_TYPE = "meter_type"

ADDON_SLUG = "core_zwave_js"
38 changes: 37 additions & 1 deletion homeassistant/components/zwave_js/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import logging
from typing import cast

import voluptuous as vol
from zwave_js_server.client import Client as ZwaveClient
from zwave_js_server.const import CommandClass, ConfigurationValueType
from zwave_js_server.model.node import Node as ZwaveNode
Expand All @@ -26,10 +27,11 @@
TEMP_FAHRENHEIT,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import entity_platform
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback

from .const import DATA_CLIENT, DOMAIN
from .const import ATTR_METER_TYPE, ATTR_VALUE, DATA_CLIENT, DOMAIN, SERVICE_RESET_METER
from .discovery import ZwaveDiscoveryInfo
from .entity import ZWaveBaseEntity
from .helpers import get_device_id
Expand Down Expand Up @@ -89,6 +91,16 @@ def async_add_node_status_sensor(node: ZwaveNode) -> None:
)
)

platform = entity_platform.async_get_current_platform()
platform.async_register_entity_service(
SERVICE_RESET_METER,
{
vol.Optional(ATTR_METER_TYPE): vol.Coerce(int),
vol.Optional(ATTR_VALUE): vol.Coerce(int),
},
"async_reset_meter",
)


class ZwaveSensorBase(ZWaveBaseEntity, SensorEntity):
"""Basic Representation of a Z-Wave sensor."""
Expand Down Expand Up @@ -218,6 +230,30 @@ def unit_of_measurement(self) -> str | None:

return str(self.info.primary_value.metadata.unit)

async def async_reset_meter(
self, meter_type: int | None = None, value: int | None = None
) -> None:
"""Reset meter(s) on device."""
node = self.info.node
primary_value = self.info.primary_value
if primary_value.command_class != CommandClass.METER:
raise TypeError("Reset only available for Meter sensors")
options = {}
if meter_type is not None:
options["type"] = meter_type
if value is not None:
options["targetValue"] = value
Comment thread
raman325 marked this conversation as resolved.
args = [options] if options else []
await node.endpoints[primary_value.endpoint].async_invoke_cc_api(
CommandClass.METER, "reset", *args, wait_for_result=False
)
LOGGER.debug(
"Meters on node %s endpoint %s reset with the following options: %s",
node,
primary_value.endpoint,
options,
)


class ZWaveListSensor(ZwaveSensorBase):
"""Representation of a Z-Wave Numeric sensor with multiple states."""
Expand Down
23 changes: 23 additions & 0 deletions homeassistant/components/zwave_js/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -229,3 +229,26 @@ ping:
target:
entity:
integration: zwave_js

reset_meter:
name: Reset meter(s) on a node
description: Resets the meter(s) on a node.
target:
entity:
domain: sensor
integration: zwave_js
fields:
meter_type:
name: Meter Type
description: The type of meter to reset. Not all meters support the ability to pick a meter type to reset.
example: 1
required: false
selector:
text:
value:
name: Target Value
description: The value that meter(s) should be reset to. Not all meters support the ability to be reset to a specific value.
example: 5
required: false
selector:
text:
59 changes: 59 additions & 0 deletions tests/components/zwave_js/test_sensor.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
"""Test the Z-Wave JS sensor platform."""
from zwave_js_server.event import Event

from homeassistant.components.zwave_js.const import (
ATTR_METER_TYPE,
ATTR_VALUE,
DOMAIN,
SERVICE_RESET_METER,
)
from homeassistant.const import (
ATTR_ENTITY_ID,
DEVICE_CLASS_ENERGY,
DEVICE_CLASS_HUMIDITY,
DEVICE_CLASS_POWER,
Expand Down Expand Up @@ -131,3 +138,55 @@ async def test_node_status_sensor(hass, lock_id_lock_as_id150, integration):
)
node.receive_event(event)
assert hass.states.get(NODE_STATUS_ENTITY).state == "alive"


async def test_reset_meter(
hass,
client,
aeon_smart_switch_6,
integration,
):
"""Test reset_meter service."""
SENSOR = "sensor.smart_switch_6_electric_consumed_v"
client.async_send_command.return_value = {}
client.async_send_command_no_wait.return_value = {}

# Test successful meter reset call
await hass.services.async_call(
DOMAIN,
SERVICE_RESET_METER,
{
ATTR_ENTITY_ID: SENSOR,
},
blocking=True,
)

assert len(client.async_send_command_no_wait.call_args_list) == 1
args = client.async_send_command_no_wait.call_args[0][0]
assert args["command"] == "endpoint.invoke_cc_api"
assert args["nodeId"] == aeon_smart_switch_6.node_id
assert args["endpoint"] == 0
assert args["args"] == []

client.async_send_command_no_wait.reset_mock()

# Test successful meter reset call with options
await hass.services.async_call(
DOMAIN,
SERVICE_RESET_METER,
{
ATTR_ENTITY_ID: SENSOR,
ATTR_METER_TYPE: 1,
ATTR_VALUE: 2,
},
blocking=True,
)

assert len(client.async_send_command_no_wait.call_args_list) == 1
args = client.async_send_command_no_wait.call_args[0][0]
assert args["command"] == "endpoint.invoke_cc_api"
assert args["nodeId"] == aeon_smart_switch_6.node_id
assert args["endpoint"] == 0
assert args["args"] == [{"type": 1, "targetValue": 2}]

client.async_send_command_no_wait.reset_mock()