Skip to content

Commit 6a6890e

Browse files
committed
Added send_instance_command service, refactored open_door service, now it's internally call send_instance_command
Updated documentation Update manifest.json Update sensor.py
1 parent d232688 commit 6a6890e

File tree

4 files changed

+161
-76
lines changed

4 files changed

+161
-76
lines changed

README.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,8 @@ lock:
159159

160160
# Commands and Events
161161

162-
You can send any command using the service `dahua_vto.send_command` and receive reply as event.
162+
You can send any command using the service `dahua_vto.send_command` or `dahua_vto.send_instance_command` and receive reply as event.
163+
`dahua_vto.send_instance_command` sequential call to service.factory.instance, service.method with object returned by factory.instance and service.destroy, where service it's a first part of the `method` before `.`. Result of service.method returned as event.
163164
I doesn't found documentation but you can grab some commands and their parameters from [Dahua-JSON-Debug-Console-v2.py](https://github.com/mcw0/Tools)
164165

165166
All device `client.notifyEventStream` messages you will receive as events, information about some of them you can find [here](https://github.com/elad-bar/DahuaVTO2MQTT/blob/master/MQTTEvents.MD).
@@ -205,6 +206,22 @@ data:
205206
entity_id: sensor.dahua_vto
206207
method: magicBox.getBootParameter
207208
params: {names: ['serverip', 'ver']}
209+
210+
# Cancel VTO Call
211+
service: dahua_vto.send_command
212+
data:
213+
entity_id: sensor.dahua_vto
214+
method: console.runCmd
215+
params: {'command': 'hc'}
216+
event: false
217+
218+
# Delete VTH Records
219+
service: dahua_vto.send_instance_command
220+
data:
221+
entity_id: sensor.dahua_vth
222+
method: RecordUpdater.clear
223+
instance_params: {'name': 'VideoTalkMissedLog'}
224+
event: false
208225
```
209226

210227
# Debugging

custom_components/dahua_vto/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"domain": "dahua_vto",
33
"name": "Dahua VTO",
4-
"version": "1.0.5",
4+
"version": "1.0.6",
55
"documentation": "https://github.com/myhomeiot/DahuaVTO",
66
"issue_tracker": "https://github.com/myhomeiot/DahuaVTO/issues",
77
"requirements": [],

custom_components/dahua_vto/sensor.py

Lines changed: 77 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -43,33 +43,47 @@
4343
CONF_CHANNEL = "channel"
4444
CONF_SHORT_NUMBER = "short_number"
4545
CONF_METHOD = "method"
46+
CONF_INSTANCE_PARAMS = "instance_params"
4647
CONF_PARAMS = "params"
4748
CONF_TAG = "tag"
4849

4950
SERVICE_DEFAULT_TIMEOUT = 5
5051

51-
SERVICE_OPEN_DOOR = "open_door"
52-
SERVICE_OPEN_DOOR_SCHEMA = vol.Schema(
52+
SERVICE_SEND_COMMAND = "send_command"
53+
SERVICE_SEND_COMMAND_SCHEMA = vol.Schema(
5354
{
5455
vol.Required(CONF_ENTITY_ID): cv.string,
55-
vol.Required(CONF_CHANNEL): int,
56-
vol.Optional(CONF_SHORT_NUMBER, default="HA"): cv.string,
56+
vol.Required(CONF_METHOD): object,
57+
vol.Optional(CONF_PARAMS, default=None): object,
58+
vol.Optional(CONF_EVENT, default=True): bool,
59+
vol.Optional(CONF_TAG, default=None): object,
5760
vol.Optional(CONF_TIMEOUT, default=SERVICE_DEFAULT_TIMEOUT): int,
5861
}
5962
)
6063

61-
SERVICE_SEND_COMMAND = "send_command"
62-
SERVICE_SEND_COMMAND_SCHEMA = vol.Schema(
64+
SERVICE_SEND_INSTANCE_COMMAND = "send_instance_command"
65+
SERVICE_SEND_INSTANCE_COMMAND_SCHEMA = vol.Schema(
6366
{
6467
vol.Required(CONF_ENTITY_ID): cv.string,
6568
vol.Required(CONF_METHOD): object,
69+
vol.Optional(CONF_INSTANCE_PARAMS, default=None): object,
6670
vol.Optional(CONF_PARAMS, default=None): object,
6771
vol.Optional(CONF_EVENT, default=True): bool,
6872
vol.Optional(CONF_TAG, default=None): object,
6973
vol.Optional(CONF_TIMEOUT, default=SERVICE_DEFAULT_TIMEOUT): int,
7074
}
7175
)
7276

77+
SERVICE_OPEN_DOOR = "open_door"
78+
SERVICE_OPEN_DOOR_SCHEMA = vol.Schema(
79+
{
80+
vol.Required(CONF_ENTITY_ID): cv.string,
81+
vol.Required(CONF_CHANNEL): int,
82+
vol.Optional(CONF_SHORT_NUMBER, default="HA"): cv.string,
83+
vol.Optional(CONF_TIMEOUT, default=SERVICE_DEFAULT_TIMEOUT): int,
84+
}
85+
)
86+
7387

7488
async def async_setup_platform(
7589
hass, config, add_entities, discovery_info=None
@@ -82,16 +96,21 @@ async def async_setup_platform(
8296
hass.loop.create_task(entity.async_run())
8397

8498
platform = entity_platform.async_get_current_platform()
85-
platform.async_register_entity_service(
86-
SERVICE_OPEN_DOOR,
87-
SERVICE_OPEN_DOOR_SCHEMA,
88-
"async_open_door"
89-
)
9099
platform.async_register_entity_service(
91100
SERVICE_SEND_COMMAND,
92101
SERVICE_SEND_COMMAND_SCHEMA,
93102
"async_send_command"
94103
)
104+
platform.async_register_entity_service(
105+
SERVICE_SEND_INSTANCE_COMMAND,
106+
SERVICE_SEND_INSTANCE_COMMAND_SCHEMA,
107+
"async_send_instance_command"
108+
)
109+
platform.async_register_entity_service(
110+
SERVICE_OPEN_DOOR,
111+
SERVICE_OPEN_DOOR_SCHEMA,
112+
"async_open_door"
113+
)
95114
return True
96115

97116

@@ -214,19 +233,6 @@ async def command(self, message, timeout=5):
214233
finally:
215234
self.on_response = self.on_response_id = None
216235

217-
async def open_door(self, channel, short_number, timeout):
218-
object_id = (await self.command({
219-
"method": "accessControl.factory.instance",
220-
"params": {"channel": channel}}, timeout))["result"]
221-
if object_id:
222-
try:
223-
await self.command({
224-
"method": "accessControl.openDoor", "object": object_id,
225-
"params": {"DoorIndex": 0, "ShortNumber": short_number}})
226-
finally:
227-
await self.command({
228-
"method": "accessControl.destroy", "object": object_id})
229-
230236
async def send_command(self, method, params, event, tag, timeout):
231237
if isinstance(method, dict):
232238
message = method
@@ -244,6 +250,29 @@ async def send_command(self, method, params, event, tag, timeout):
244250
result["entity_id"] = self.entity.entity_id
245251
self.hass.bus.fire(DOMAIN, result)
246252

253+
async def send_instance_command(
254+
self, method, instance_params, params, event, tag, timeout
255+
):
256+
service = method.partition('.')[0]
257+
object_id = (await self.command({
258+
"method": f"{service}.factory.instance",
259+
"params": instance_params}, timeout))["result"]
260+
if object_id:
261+
try:
262+
result = await self.command({
263+
"method": method, "object": object_id, "params": params})
264+
if event:
265+
del result["id"]
266+
del result["session"]
267+
result["method"] = method
268+
if tag:
269+
result["tag"] = tag
270+
result["entity_id"] = self.entity.entity_id
271+
self.hass.bus.fire(DOMAIN, result)
272+
finally:
273+
await self.command({
274+
"method": f"{service}.destroy", "object": object_id})
275+
247276
async def heartbeat_loop(self):
248277
result = await self.command({"method": "magicBox.getSystemInfo"})
249278
if result.get("result"):
@@ -327,20 +356,38 @@ def state_attributes(self):
327356
def update(self):
328357
self._state = 'OK' if self.protocol is not None else None
329358

330-
async def async_open_door(self, channel, short_number, timeout) -> None:
359+
async def async_send_command(
360+
self, method, params, event, tag, timeout
361+
) -> None:
331362
if self.protocol is None:
332363
raise HomeAssistantError("not connected")
333364
try:
334-
await self.protocol.open_door(channel - 1, short_number, timeout)
365+
await self.protocol.send_command(
366+
method, params, event, tag, timeout
367+
)
335368
except asyncio.TimeoutError:
336369
raise HomeAssistantError("timeout")
337370

338-
async def async_send_command(self, method, params,
339-
event, tag, timeout) -> None:
371+
async def async_send_instance_command(
372+
self, method, instance_params, params, event, tag, timeout
373+
) -> None:
374+
if self.protocol is None:
375+
raise HomeAssistantError("not connected")
376+
try:
377+
await self.protocol.send_instance_command(
378+
method, instance_params, params, event, tag, timeout
379+
)
380+
except asyncio.TimeoutError:
381+
raise HomeAssistantError("timeout")
382+
383+
async def async_open_door(self, channel, short_number, timeout) -> None:
340384
if self.protocol is None:
341385
raise HomeAssistantError("not connected")
342386
try:
343-
await self.protocol.send_command(method, params,
344-
event, tag, timeout)
387+
await self.protocol.send_instance_command(
388+
"accessControl.openDoor", {"channel": channel - 1},
389+
{"DoorIndex": 0, "ShortNumber": short_number},
390+
None, None, timeout
391+
)
345392
except asyncio.TimeoutError:
346393
raise HomeAssistantError("timeout")
Lines changed: 65 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
open_door:
2-
name: Open door
3-
description: Open the door
1+
send_command:
2+
name: Send command
3+
description: Send the command
44
fields:
55
<<: &entity_id
66
entity_id:
@@ -11,22 +11,36 @@ open_door:
1111
selector:
1212
entity:
1313
domain: sensor
14-
channel:
15-
name: Channel
16-
description: Number of channel starting from 1
17-
required: true
18-
example: 1
19-
selector:
20-
number:
21-
min: 1
22-
max: 15
23-
short_number:
24-
name: Short Number
25-
description: Short number to show in the log as Room No.
26-
default: HA
27-
example: HA
28-
selector:
29-
text:
14+
<<: &method
15+
method:
16+
name: Method
17+
description: "Method name, example: magicBox.getBootParameter"
18+
required: true
19+
example: system.listService
20+
selector:
21+
object:
22+
<<: &params
23+
params:
24+
name: Params
25+
description: "Method parameters, example: {names: ['serverip', 'ver']}"
26+
example: "{names: ['serverip', 'ver']}"
27+
selector:
28+
object:
29+
<<: &event
30+
event:
31+
name: Event
32+
description: Fire event with result
33+
default: True
34+
example: True
35+
selector:
36+
boolean:
37+
<<: &tag
38+
tag:
39+
name: Tag
40+
description: "Tag, will be present in event data, example: 1 or {name: tag}"
41+
example: "{name: tag}"
42+
selector:
43+
object:
3044
<<: &timeout
3145
timeout:
3246
name: Timeout
@@ -38,35 +52,42 @@ open_door:
3852
min: 1
3953
max: 99
4054

41-
send_command:
42-
name: Send command
43-
description: Send the command
55+
send_instance_command:
56+
name: Send instance command
57+
description: Send the command to the instance, sequential call to service.factory.instance, service.method with object returned by factory.instance, service.destroy
4458
fields:
4559
<<: *entity_id
46-
method:
47-
name: Method
48-
description: "Method name, example: magicBox.getBootParameter"
49-
required: true
50-
example: system.listService
60+
<<: *method
61+
instance_params:
62+
name: Instance params
63+
description: "Instance method parameters, for service.factory.instance call, example: {'name': 'VideoTalkMissedLog'}"
64+
example: "{'name': 'VideoTalkMissedLog'}"
5165
selector:
5266
object:
53-
params:
54-
name: Params
55-
description: "Method parameters, example: {names: ['serverip', 'ver']}"
56-
example: "{names: ['serverip', 'ver']}"
57-
selector:
58-
object:
59-
event:
60-
name: Event
61-
description: Fire event with result
62-
default: True
63-
example: True
67+
<<: *params
68+
<<: *event
69+
<<: *tag
70+
<<: *timeout
71+
72+
open_door:
73+
name: Open door
74+
description: Open the door
75+
fields:
76+
<<: *entity_id
77+
channel:
78+
name: Channel
79+
description: Number of channel starting from 1
80+
required: true
81+
example: 1
6482
selector:
65-
boolean:
66-
tag:
67-
name: Tag
68-
description: "Tag, will be present in event data, example: 1 or {name: tag}"
69-
example: "{name: tag}"
83+
number:
84+
min: 1
85+
max: 15
86+
short_number:
87+
name: Short number
88+
description: Short number to show in the log as Room No.
89+
default: HA
90+
example: HA
7091
selector:
71-
object:
92+
text:
7293
<<: *timeout

0 commit comments

Comments
 (0)