Skip to content

Commit 94e4362

Browse files
committed
fix: event watch has reliable json output
Why: * event watch is dumping Dict rather than json * event watch is not honoring output formats This change addreses the need by: * add callback mechanism for websocket calls * used usual formatter for every message Means event watch dumps 1 table per msg. Recommended to use --no-headers * Made formatting just dump one item when output is not actually a list. * Only print `event` messages
1 parent fd44bf2 commit 94e4362

File tree

4 files changed

+40
-12
lines changed

4 files changed

+40
-12
lines changed

homeassistant_cli/const.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
DEFAULT_DATAOUTPUT = 'yaml'
1515

16-
COLUMNS_DEFAULT = [('ALL', '*')]
16+
COLUMNS_DEFAULT = [('ALL', '$')]
1717
COLUMNS_ENTITIES = [
1818
('ENTITY', 'entity_id'),
1919
('DESCRIPTION', 'attributes.friendly_name'),

homeassistant_cli/helper.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import json
55
import logging
66
import shlex
7-
from typing import Any, Dict, Generator, List, Optional, Tuple, cast
7+
from typing import Any, Dict, Generator, List, Optional, Tuple, Union, cast
88

99
from homeassistant_cli.config import Configuration
1010
import homeassistant_cli.const as const
@@ -47,7 +47,7 @@ def to_tuples(entry: str) -> List[Tuple[str, str]]:
4747

4848
def raw_format_output(
4949
output: str,
50-
data: List[Dict[str, Any]],
50+
data: Union[Dict[str, Any], List[Dict[str, Any]]],
5151
yamlparser: YAML,
5252
columns: Optional[List] = None,
5353
no_headers: bool = False,
@@ -59,7 +59,7 @@ def raw_format_output(
5959
_LOGGING.debug("Output `auto` thus using %s", const.DEFAULT_DATAOUTPUT)
6060
output = const.DEFAULT_DATAOUTPUT
6161

62-
if sort_by:
62+
if sort_by and isinstance(data, List):
6363
_sort_table(data, sort_by)
6464

6565
if output == 'json':
@@ -79,17 +79,24 @@ def raw_format_output(
7979
columns = const.COLUMNS_DEFAULT
8080

8181
fmt = [(v[0], parse(v[1] if len(v) > 1 else v[0])) for v in columns]
82+
8283
result = []
84+
8385
if no_headers:
8486
headers = [] # type: List[str]
8587
else:
8688
headers = [v[0] for v in fmt]
89+
90+
# in case data passed in is a single element
91+
# we turn it into a single item list for better table output
92+
if not isinstance(data, List):
93+
data = [data]
94+
8795
for item in data:
8896
row = []
8997
for fmtpair in fmt:
9098
val = [match.value for match in fmtpair[1].find(item)]
9199
row.append(", ".join(map(str, val)))
92-
93100
result.append(row)
94101

95102
res = tabulate(

homeassistant_cli/plugins/event.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
"""Event plugin for Home Assistant CLI (hass-cli)."""
22
import json as json_
33
import logging
4+
from typing import Dict
45

56
import click
67
import homeassistant_cli.autocompletion as autocompletion
78
from homeassistant_cli.cli import pass_context
89
from homeassistant_cli.config import Configuration
9-
from homeassistant_cli.helper import raw_format_output
10+
from homeassistant_cli.helper import format_output, raw_format_output
1011
import homeassistant_cli.remote as api
1112

1213
_LOGGING = logging.getLogger(__name__)
@@ -63,7 +64,19 @@ def watch(ctx: Configuration, event_type):
6364
"""
6465
frame = {'type': 'subscribe_events'}
6566

67+
cols = [('EVENT_TYPE', 'event_type'), ('DATA', '$.data')]
68+
69+
def _msghandler(msg: Dict) -> None:
70+
if msg['type'] == 'event':
71+
ctx.echo(
72+
format_output(
73+
ctx,
74+
msg['event'],
75+
columns=ctx.columns if ctx.columns else cols,
76+
)
77+
)
78+
6679
if event_type:
6780
frame['event_type'] = event_type
6881

69-
api.wsapi(ctx, frame, True)
82+
api.wsapi(ctx, frame, _msghandler)

homeassistant_cli/remote.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import enum
1111
import json
1212
import logging
13-
from typing import Any, Dict, List, Optional, cast
13+
from typing import Any, Callable, Dict, List, Optional, cast
1414
import urllib.parse
1515
from urllib.parse import urlencode
1616

@@ -88,9 +88,17 @@ def restapi(
8888

8989

9090
def wsapi(
91-
ctx: Configuration, frame: Dict, wait: bool = False
91+
ctx: Configuration,
92+
frame: Dict,
93+
callback: Optional[Callable[[Dict], Any]] = None,
9294
) -> Optional[Dict]:
93-
"""Make a call to Home Assistant using WS API."""
95+
"""Make a call to Home Assistant using WS API.
96+
97+
if callback provided will keep listening and call
98+
on every message.
99+
100+
If no callback return data returned.
101+
"""
94102
loop = asyncio.get_event_loop()
95103

96104
async def fetcher() -> Optional[Dict]:
@@ -116,8 +124,8 @@ async def fetcher() -> Optional[Dict]:
116124
elif msg.type == aiohttp.WSMsgType.TEXT:
117125
mydata = json.loads(msg.data) # type: Dict
118126

119-
if wait:
120-
print(mydata)
127+
if callback:
128+
callback(mydata)
121129
elif mydata['type'] == 'result':
122130
return mydata
123131
return None

0 commit comments

Comments
 (0)