Skip to content

Commit

Permalink
Added send_instance_command service, refactored open_door service, no…
Browse files Browse the repository at this point in the history
…w it's internally call send_instance_command

Updated documentation

Update manifest.json

Update sensor.py
  • Loading branch information
myhomeiot committed Sep 13, 2021
1 parent d232688 commit 6a6890e
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 76 deletions.
19 changes: 18 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,8 @@ lock:

# Commands and Events

You can send any command using the service `dahua_vto.send_command` and receive reply as event.
You can send any command using the service `dahua_vto.send_command` or `dahua_vto.send_instance_command` and receive reply as event.
`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.
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)

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).
Expand Down Expand Up @@ -205,6 +206,22 @@ data:
entity_id: sensor.dahua_vto
method: magicBox.getBootParameter
params: {names: ['serverip', 'ver']}
# Cancel VTO Call
service: dahua_vto.send_command
data:
entity_id: sensor.dahua_vto
method: console.runCmd
params: {'command': 'hc'}
event: false
# Delete VTH Records
service: dahua_vto.send_instance_command
data:
entity_id: sensor.dahua_vth
method: RecordUpdater.clear
instance_params: {'name': 'VideoTalkMissedLog'}
event: false
```

# Debugging
Expand Down
2 changes: 1 addition & 1 deletion custom_components/dahua_vto/manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"domain": "dahua_vto",
"name": "Dahua VTO",
"version": "1.0.5",
"version": "1.0.6",
"documentation": "https://github.com/myhomeiot/DahuaVTO",
"issue_tracker": "https://github.com/myhomeiot/DahuaVTO/issues",
"requirements": [],
Expand Down
107 changes: 77 additions & 30 deletions custom_components/dahua_vto/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,33 +43,47 @@
CONF_CHANNEL = "channel"
CONF_SHORT_NUMBER = "short_number"
CONF_METHOD = "method"
CONF_INSTANCE_PARAMS = "instance_params"
CONF_PARAMS = "params"
CONF_TAG = "tag"

SERVICE_DEFAULT_TIMEOUT = 5

SERVICE_OPEN_DOOR = "open_door"
SERVICE_OPEN_DOOR_SCHEMA = vol.Schema(
SERVICE_SEND_COMMAND = "send_command"
SERVICE_SEND_COMMAND_SCHEMA = vol.Schema(
{
vol.Required(CONF_ENTITY_ID): cv.string,
vol.Required(CONF_CHANNEL): int,
vol.Optional(CONF_SHORT_NUMBER, default="HA"): cv.string,
vol.Required(CONF_METHOD): object,
vol.Optional(CONF_PARAMS, default=None): object,
vol.Optional(CONF_EVENT, default=True): bool,
vol.Optional(CONF_TAG, default=None): object,
vol.Optional(CONF_TIMEOUT, default=SERVICE_DEFAULT_TIMEOUT): int,
}
)

SERVICE_SEND_COMMAND = "send_command"
SERVICE_SEND_COMMAND_SCHEMA = vol.Schema(
SERVICE_SEND_INSTANCE_COMMAND = "send_instance_command"
SERVICE_SEND_INSTANCE_COMMAND_SCHEMA = vol.Schema(
{
vol.Required(CONF_ENTITY_ID): cv.string,
vol.Required(CONF_METHOD): object,
vol.Optional(CONF_INSTANCE_PARAMS, default=None): object,
vol.Optional(CONF_PARAMS, default=None): object,
vol.Optional(CONF_EVENT, default=True): bool,
vol.Optional(CONF_TAG, default=None): object,
vol.Optional(CONF_TIMEOUT, default=SERVICE_DEFAULT_TIMEOUT): int,
}
)

SERVICE_OPEN_DOOR = "open_door"
SERVICE_OPEN_DOOR_SCHEMA = vol.Schema(
{
vol.Required(CONF_ENTITY_ID): cv.string,
vol.Required(CONF_CHANNEL): int,
vol.Optional(CONF_SHORT_NUMBER, default="HA"): cv.string,
vol.Optional(CONF_TIMEOUT, default=SERVICE_DEFAULT_TIMEOUT): int,
}
)


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

platform = entity_platform.async_get_current_platform()
platform.async_register_entity_service(
SERVICE_OPEN_DOOR,
SERVICE_OPEN_DOOR_SCHEMA,
"async_open_door"
)
platform.async_register_entity_service(
SERVICE_SEND_COMMAND,
SERVICE_SEND_COMMAND_SCHEMA,
"async_send_command"
)
platform.async_register_entity_service(
SERVICE_SEND_INSTANCE_COMMAND,
SERVICE_SEND_INSTANCE_COMMAND_SCHEMA,
"async_send_instance_command"
)
platform.async_register_entity_service(
SERVICE_OPEN_DOOR,
SERVICE_OPEN_DOOR_SCHEMA,
"async_open_door"
)
return True


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

async def open_door(self, channel, short_number, timeout):
object_id = (await self.command({
"method": "accessControl.factory.instance",
"params": {"channel": channel}}, timeout))["result"]
if object_id:
try:
await self.command({
"method": "accessControl.openDoor", "object": object_id,
"params": {"DoorIndex": 0, "ShortNumber": short_number}})
finally:
await self.command({
"method": "accessControl.destroy", "object": object_id})

async def send_command(self, method, params, event, tag, timeout):
if isinstance(method, dict):
message = method
Expand All @@ -244,6 +250,29 @@ async def send_command(self, method, params, event, tag, timeout):
result["entity_id"] = self.entity.entity_id
self.hass.bus.fire(DOMAIN, result)

async def send_instance_command(
self, method, instance_params, params, event, tag, timeout
):
service = method.partition('.')[0]
object_id = (await self.command({
"method": f"{service}.factory.instance",
"params": instance_params}, timeout))["result"]
if object_id:
try:
result = await self.command({
"method": method, "object": object_id, "params": params})
if event:
del result["id"]
del result["session"]
result["method"] = method
if tag:
result["tag"] = tag
result["entity_id"] = self.entity.entity_id
self.hass.bus.fire(DOMAIN, result)
finally:
await self.command({
"method": f"{service}.destroy", "object": object_id})

async def heartbeat_loop(self):
result = await self.command({"method": "magicBox.getSystemInfo"})
if result.get("result"):
Expand Down Expand Up @@ -327,20 +356,38 @@ def state_attributes(self):
def update(self):
self._state = 'OK' if self.protocol is not None else None

async def async_open_door(self, channel, short_number, timeout) -> None:
async def async_send_command(
self, method, params, event, tag, timeout
) -> None:
if self.protocol is None:
raise HomeAssistantError("not connected")
try:
await self.protocol.open_door(channel - 1, short_number, timeout)
await self.protocol.send_command(
method, params, event, tag, timeout
)
except asyncio.TimeoutError:
raise HomeAssistantError("timeout")

async def async_send_command(self, method, params,
event, tag, timeout) -> None:
async def async_send_instance_command(
self, method, instance_params, params, event, tag, timeout
) -> None:
if self.protocol is None:
raise HomeAssistantError("not connected")
try:
await self.protocol.send_instance_command(
method, instance_params, params, event, tag, timeout
)
except asyncio.TimeoutError:
raise HomeAssistantError("timeout")

async def async_open_door(self, channel, short_number, timeout) -> None:
if self.protocol is None:
raise HomeAssistantError("not connected")
try:
await self.protocol.send_command(method, params,
event, tag, timeout)
await self.protocol.send_instance_command(
"accessControl.openDoor", {"channel": channel - 1},
{"DoorIndex": 0, "ShortNumber": short_number},
None, None, timeout
)
except asyncio.TimeoutError:
raise HomeAssistantError("timeout")
109 changes: 65 additions & 44 deletions custom_components/dahua_vto/services.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
open_door:
name: Open door
description: Open the door
send_command:
name: Send command
description: Send the command
fields:
<<: &entity_id
entity_id:
Expand All @@ -11,22 +11,36 @@ open_door:
selector:
entity:
domain: sensor
channel:
name: Channel
description: Number of channel starting from 1
required: true
example: 1
selector:
number:
min: 1
max: 15
short_number:
name: Short Number
description: Short number to show in the log as Room No.
default: HA
example: HA
selector:
text:
<<: &method
method:
name: Method
description: "Method name, example: magicBox.getBootParameter"
required: true
example: system.listService
selector:
object:
<<: &params
params:
name: Params
description: "Method parameters, example: {names: ['serverip', 'ver']}"
example: "{names: ['serverip', 'ver']}"
selector:
object:
<<: &event
event:
name: Event
description: Fire event with result
default: True
example: True
selector:
boolean:
<<: &tag
tag:
name: Tag
description: "Tag, will be present in event data, example: 1 or {name: tag}"
example: "{name: tag}"
selector:
object:
<<: &timeout
timeout:
name: Timeout
Expand All @@ -38,35 +52,42 @@ open_door:
min: 1
max: 99

send_command:
name: Send command
description: Send the command
send_instance_command:
name: Send instance command
description: Send the command to the instance, sequential call to service.factory.instance, service.method with object returned by factory.instance, service.destroy
fields:
<<: *entity_id
method:
name: Method
description: "Method name, example: magicBox.getBootParameter"
required: true
example: system.listService
<<: *method
instance_params:
name: Instance params
description: "Instance method parameters, for service.factory.instance call, example: {'name': 'VideoTalkMissedLog'}"
example: "{'name': 'VideoTalkMissedLog'}"
selector:
object:
params:
name: Params
description: "Method parameters, example: {names: ['serverip', 'ver']}"
example: "{names: ['serverip', 'ver']}"
selector:
object:
event:
name: Event
description: Fire event with result
default: True
example: True
<<: *params
<<: *event
<<: *tag
<<: *timeout

open_door:
name: Open door
description: Open the door
fields:
<<: *entity_id
channel:
name: Channel
description: Number of channel starting from 1
required: true
example: 1
selector:
boolean:
tag:
name: Tag
description: "Tag, will be present in event data, example: 1 or {name: tag}"
example: "{name: tag}"
number:
min: 1
max: 15
short_number:
name: Short number
description: Short number to show in the log as Room No.
default: HA
example: HA
selector:
object:
text:
<<: *timeout

0 comments on commit 6a6890e

Please sign in to comment.