Add basic websocket api for OZW (#38265)
parent
c5ca484eaa
commit
13e8e28778
|
@ -35,6 +35,7 @@ from .entity import (
|
|||
create_value_id,
|
||||
)
|
||||
from .services import ZWaveServices
|
||||
from .websocket_api import ZWaveWebsocketApi
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -206,6 +207,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
|
|||
services = ZWaveServices(hass, manager)
|
||||
services.async_register()
|
||||
|
||||
# Register WebSocket API
|
||||
ws_api = ZWaveWebsocketApi(hass, manager)
|
||||
ws_api.async_register_api()
|
||||
|
||||
@callback
|
||||
def async_receive_message(msg):
|
||||
manager.receive_message(msg.topic, msg.payload)
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
"""Web socket API for OpenZWave."""
|
||||
|
||||
import logging
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components import websocket_api
|
||||
from homeassistant.core import callback
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
TYPE = "type"
|
||||
ID = "id"
|
||||
OZW_INSTANCE = "ozw_instance"
|
||||
NODE_ID = "node_id"
|
||||
|
||||
|
||||
class ZWaveWebsocketApi:
|
||||
"""Class that holds our websocket api commands."""
|
||||
|
||||
def __init__(self, hass, manager):
|
||||
"""Initialize with both hass and ozwmanager objects."""
|
||||
self._hass = hass
|
||||
self._manager = manager
|
||||
|
||||
@callback
|
||||
def async_register_api(self):
|
||||
"""Register all of our api endpoints."""
|
||||
websocket_api.async_register_command(self._hass, self.websocket_network_status)
|
||||
websocket_api.async_register_command(self._hass, self.websocket_node_status)
|
||||
websocket_api.async_register_command(self._hass, self.websocket_node_statistics)
|
||||
|
||||
@websocket_api.websocket_command(
|
||||
{
|
||||
vol.Required(TYPE): "ozw/network_status",
|
||||
vol.Optional(OZW_INSTANCE, default=1): vol.Coerce(int),
|
||||
}
|
||||
)
|
||||
def websocket_network_status(self, hass, connection, msg):
|
||||
"""Get Z-Wave network status."""
|
||||
|
||||
connection.send_result(
|
||||
msg[ID],
|
||||
{
|
||||
"state": self._manager.get_instance(msg[OZW_INSTANCE])
|
||||
.get_status()
|
||||
.status,
|
||||
OZW_INSTANCE: msg[OZW_INSTANCE],
|
||||
},
|
||||
)
|
||||
|
||||
@websocket_api.websocket_command(
|
||||
{
|
||||
vol.Required(TYPE): "ozw/node_status",
|
||||
vol.Required(NODE_ID): vol.Coerce(int),
|
||||
vol.Optional(OZW_INSTANCE, default=1): vol.Coerce(int),
|
||||
}
|
||||
)
|
||||
def websocket_node_status(self, hass, connection, msg):
|
||||
"""Get the status for a Z-Wave node."""
|
||||
|
||||
node = self._manager.get_instance(msg[OZW_INSTANCE]).get_node(msg[NODE_ID])
|
||||
connection.send_result(
|
||||
msg[ID],
|
||||
{
|
||||
"node_query_stage": node.node_query_stage,
|
||||
"node_id": node.node_id,
|
||||
"is_zwave_plus": node.is_zwave_plus,
|
||||
"is_awake": node.is_awake,
|
||||
"is_failed": node.is_failed,
|
||||
"node_baud_rate": node.node_baud_rate,
|
||||
"is_beaming": node.is_beaming,
|
||||
"is_flirs": node.is_flirs,
|
||||
"is_routing": node.is_routing,
|
||||
"is_securityv1": node.is_securityv1,
|
||||
"node_basic_string": node.node_basic_string,
|
||||
"node_generic_string": node.node_generic_string,
|
||||
"node_specific_string": node.node_specific_string,
|
||||
OZW_INSTANCE: msg[OZW_INSTANCE],
|
||||
},
|
||||
)
|
||||
|
||||
@websocket_api.websocket_command(
|
||||
{
|
||||
vol.Required(TYPE): "ozw/node_statistics",
|
||||
vol.Required(NODE_ID): vol.Coerce(int),
|
||||
vol.Optional(OZW_INSTANCE, default=1): vol.Coerce(int),
|
||||
}
|
||||
)
|
||||
def websocket_node_statistics(self, hass, connection, msg):
|
||||
"""Get the statistics for a Z-Wave node."""
|
||||
|
||||
stats = (
|
||||
self._manager.get_instance(msg[OZW_INSTANCE])
|
||||
.get_node(msg[NODE_ID])
|
||||
.get_statistics()
|
||||
)
|
||||
connection.send_result(
|
||||
msg[ID],
|
||||
{
|
||||
"node_id": msg[NODE_ID],
|
||||
"send_count": stats.send_count,
|
||||
"sent_failed": stats.sent_failed,
|
||||
"retries": stats.retries,
|
||||
"last_request_rtt": stats.last_request_rtt,
|
||||
"last_response_rtt": stats.last_response_rtt,
|
||||
"average_request_rtt": stats.average_request_rtt,
|
||||
"average_response_rtt": stats.average_response_rtt,
|
||||
"received_packets": stats.received_packets,
|
||||
"received_dup_packets": stats.received_dup_packets,
|
||||
"received_unsolicited": stats.received_unsolicited,
|
||||
OZW_INSTANCE: msg[OZW_INSTANCE],
|
||||
},
|
||||
)
|
|
@ -0,0 +1,57 @@
|
|||
"""Test OpenZWave Websocket API."""
|
||||
|
||||
from homeassistant.components.ozw.websocket_api import ID, NODE_ID, OZW_INSTANCE, TYPE
|
||||
|
||||
from .common import setup_ozw
|
||||
|
||||
|
||||
async def test_websocket_api(hass, generic_data, hass_ws_client):
|
||||
"""Test the ozw websocket api."""
|
||||
await setup_ozw(hass, fixture=generic_data)
|
||||
client = await hass_ws_client(hass)
|
||||
|
||||
# Test network status
|
||||
await client.send_json({ID: 5, TYPE: "ozw/network_status"})
|
||||
msg = await client.receive_json()
|
||||
result = msg["result"]
|
||||
|
||||
assert result["state"] == "driverAllNodesQueried"
|
||||
assert result[OZW_INSTANCE] == 1
|
||||
|
||||
# Test node status
|
||||
await client.send_json({ID: 6, TYPE: "ozw/node_status", NODE_ID: 32})
|
||||
msg = await client.receive_json()
|
||||
result = msg["result"]
|
||||
|
||||
assert result[OZW_INSTANCE] == 1
|
||||
assert result[NODE_ID] == 32
|
||||
assert result["node_query_stage"] == "Complete"
|
||||
assert result["is_zwave_plus"]
|
||||
assert result["is_awake"]
|
||||
assert not result["is_failed"]
|
||||
assert result["node_baud_rate"] == 100000
|
||||
assert result["is_beaming"]
|
||||
assert not result["is_flirs"]
|
||||
assert result["is_routing"]
|
||||
assert not result["is_securityv1"]
|
||||
assert result["node_basic_string"] == "Routing Slave"
|
||||
assert result["node_generic_string"] == "Binary Switch"
|
||||
assert result["node_specific_string"] == "Binary Power Switch"
|
||||
|
||||
# Test node statistics
|
||||
await client.send_json({ID: 7, TYPE: "ozw/node_statistics", NODE_ID: 39})
|
||||
msg = await client.receive_json()
|
||||
result = msg["result"]
|
||||
|
||||
assert result[OZW_INSTANCE] == 1
|
||||
assert result[NODE_ID] == 39
|
||||
assert result["send_count"] == 57
|
||||
assert result["sent_failed"] == 0
|
||||
assert result["retries"] == 1
|
||||
assert result["last_request_rtt"] == 26
|
||||
assert result["last_response_rtt"] == 38
|
||||
assert result["average_request_rtt"] == 29
|
||||
assert result["average_response_rtt"] == 37
|
||||
assert result["received_packets"] == 3594
|
||||
assert result["received_dup_packets"] == 12
|
||||
assert result["received_unsolicited"] == 3546
|
|
@ -279,4 +279,5 @@ OpenZWave/1/node/39/association/1/,{ "Name": "Lifeline", "Help": "", "M
|
|||
OpenZWave/1/node/39/instance/1/commandclass/43/,{ "Instance": 1, "CommandClassId": 43, "CommandClass": "COMMAND_CLASS_SCENE_ACTIVATION", "TimeStamp": 1579566891}
|
||||
OpenZWave/1/node/39/instance/1/commandclass/43/value/562950622511127/,{ "Label": "Scene", "Value": 0, "Units": "", "Min": -2147483648, "Max": 2147483647, "Type": "Int", "Instance": 1, "CommandClass": "COMMAND_CLASS_SCENE_ACTIVATION", "Index": 0, "Node": 7, "Genre": "User", "Help": "", "ValueIDKey": 122339347, "ReadOnly": false, "WriteOnly": false, "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Event": "valueChanged", "TimeStamp": 1579630367}
|
||||
OpenZWave/1/node/39/instance/1/commandclass/91/,{ "Instance": 1, "CommandClassId": 91, "CommandClass": "COMMAND_CLASS_CENTRAL_SCENE", "TimeStamp": 1579630630}
|
||||
OpenZWave/1/node/39/instance/1/commandclass/91/value/281476005806100/,{ "Label": "Scene 1", "Value": { "List": [ { "Value": 0, "Label": "Inactive" }, { "Value": 1, "Label": "Pressed 1 Time" }, { "Value": 2, "Label": "Key Released" }, { "Value": 3, "Label": "Key Held down" } ], "Selected": "Inactive", "Selected_id": 0 }, "Units": "", "Min": 0, "Max": 0, "Type": "List", "Instance": 1, "CommandClass": "COMMAND_CLASS_CENTRAL_SCENE", "Index": 1, "Node": 61, "Genre": "User", "Help": "", "ValueIDKey": 281476005806100, "ReadOnly": false, "WriteOnly": false, "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Event": "valueChanged", "TimeStamp": 1579640710}
|
||||
OpenZWave/1/node/39/instance/1/commandclass/91/value/281476005806100/,{ "Label": "Scene 1", "Value": { "List": [ { "Value": 0, "Label": "Inactive" }, { "Value": 1, "Label": "Pressed 1 Time" }, { "Value": 2, "Label": "Key Released" }, { "Value": 3, "Label": "Key Held down" } ], "Selected": "Inactive", "Selected_id": 0 }, "Units": "", "Min": 0, "Max": 0, "Type": "List", "Instance": 1, "CommandClass": "COMMAND_CLASS_CENTRAL_SCENE", "Index": 1, "Node": 61, "Genre": "User", "Help": "", "ValueIDKey": 281476005806100, "ReadOnly": false, "WriteOnly": false, "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Event": "valueChanged", "TimeStamp": 1579640710}
|
||||
OpenZWave/1/node/39/statistics/,{ "sendCount": 57, "sentFailed": 0, "retries": 1, "receivedPackets": 3594, "receivedDupPackets": 12, "receivedUnsolicited": 3546, "lastSentTimeStamp": 1595764791, "lastReceivedTimeStamp": 1595802261, "lastRequestRTT": 26, "averageRequestRTT": 29, "lastResponseRTT": 38, "averageResponseRTT": 37, "quality": 0, "extendedTXSupported": false, "txTime": 0, "hops": 0, "rssi_1": "", "rssi_2": "", "rssi_3": "", "rssi_4": "", "rssi_5": "", "route_1": 0, "route_2": 0, "route_3": 0, "route_4": 0, "ackChannel": 0, "lastTXChannel": 0, "routeScheme": "Idle", "routeUsed": "", "routeSpeed": "Auto", "routeTries": 0, "lastFailedLinkFrom": 0, "lastFailedLinkTo": 0}
|
Can't render this file because it contains an unexpected character in line 1 and column 26.
|
Loading…
Reference in New Issue