initial commit
This commit is contained in:
commit
97699c6c2d
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"python.formatting.provider": "black",
|
||||||
|
"python.linting.flake8Enabled": false,
|
||||||
|
"python.linting.pylintEnabled": true,
|
||||||
|
"python.linting.enabled": true
|
||||||
|
}
|
|
@ -0,0 +1,101 @@
|
||||||
|
"""Support for ZoneMinder."""
|
||||||
|
import logging
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
|
import voluptuous as vol
|
||||||
|
from zoneminder.zm import ZoneMinder
|
||||||
|
|
||||||
|
from homeassistant.const import (
|
||||||
|
ATTR_ID,
|
||||||
|
ATTR_NAME,
|
||||||
|
CONF_HOST,
|
||||||
|
CONF_NAME,
|
||||||
|
CONF_PASSWORD,
|
||||||
|
CONF_PATH,
|
||||||
|
CONF_SSL,
|
||||||
|
CONF_TTL,
|
||||||
|
CONF_USERNAME,
|
||||||
|
CONF_VERIFY_SSL,
|
||||||
|
Platform,
|
||||||
|
)
|
||||||
|
from homeassistant.core import HomeAssistant, ServiceCall
|
||||||
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
from homeassistant.helpers.discovery import async_load_platform
|
||||||
|
from homeassistant.helpers.typing import ConfigType
|
||||||
|
from homeassistant.components.zoneminder import DOMAIN as ZONEMINDER_DOMAIN
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
DOMAIN = "zoneminder_alarm"
|
||||||
|
|
||||||
|
DELAY = 10
|
||||||
|
|
||||||
|
SERVICE_TRIGGER_ALARM_STATE = "trigger_alarm_state"
|
||||||
|
TRIGGER_ALARM_SCHEMA = vol.Schema(
|
||||||
|
{vol.Required(ATTR_ID): cv.string, vol.Required(ATTR_NAME): cv.string}
|
||||||
|
)
|
||||||
|
|
||||||
|
ALARM_COMMAND_ON = "on"
|
||||||
|
ALARM_COMMAND_OFF = "off"
|
||||||
|
ALARM_COMMAND_STATUS = "status"
|
||||||
|
ALARM_STATUS_URL = "api/monitors/alarm/id:{monitor_id}/command:{command}.json"
|
||||||
|
|
||||||
|
|
||||||
|
def setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||||
|
"""Set up the ZoneMinder component."""
|
||||||
|
hass.data.setdefault(DOMAIN, {})
|
||||||
|
|
||||||
|
for conf in config[DOMAIN]:
|
||||||
|
zm_id = conf.get(CONF_HOST)
|
||||||
|
hass.data[DOMAIN].setdefault(zm_id, {})
|
||||||
|
|
||||||
|
def trigger_alarm_state(call: ServiceCall) -> None:
|
||||||
|
zm_id = call.data[ATTR_NAME]
|
||||||
|
monitor_id = call.data[ATTR_ID]
|
||||||
|
client = hass.data[ZONEMINDER_DOMAIN][zm_id]
|
||||||
|
|
||||||
|
def get_alarm_status():
|
||||||
|
result = client.get_state(
|
||||||
|
ALARM_STATUS_URL.format(
|
||||||
|
monitor_id=monitor_id, command=ALARM_COMMAND_STATUS
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return int(result["status"])
|
||||||
|
|
||||||
|
def set_alarm_on():
|
||||||
|
result = client.get_state(
|
||||||
|
ALARM_STATUS_URL.format(monitor_id=monitor_id, command=ALARM_COMMAND_ON)
|
||||||
|
)
|
||||||
|
return result["status"]
|
||||||
|
|
||||||
|
def set_alarm_off():
|
||||||
|
result = client.get_state(
|
||||||
|
ALARM_STATUS_URL.format(
|
||||||
|
monitor_id=monitor_id, command=ALARM_COMMAND_OFF
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return result["status"]
|
||||||
|
|
||||||
|
if get_alarm_status() == 0:
|
||||||
|
set_alarm_on()
|
||||||
|
hass.data[DOMAIN][zm_id][monitor_id] = DELAY
|
||||||
|
|
||||||
|
while hass.data[DOMAIN][zm_id][monitor_id] > 0:
|
||||||
|
sleep(1)
|
||||||
|
hass.data[DOMAIN][zm_id][monitor_id] -= 1
|
||||||
|
|
||||||
|
set_alarm_off()
|
||||||
|
else:
|
||||||
|
hass.data[DOMAIN][zm_id][monitor_id] += DELAY
|
||||||
|
|
||||||
|
hass.services.register(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_TRIGGER_ALARM_STATE,
|
||||||
|
trigger_alarm_state,
|
||||||
|
schema=TRIGGER_ALARM_SCHEMA,
|
||||||
|
)
|
||||||
|
|
||||||
|
platforms = (Platform.SWITCH, Platform.SENSOR)
|
||||||
|
for platform in platforms:
|
||||||
|
hass.async_create_task(async_load_platform(hass, platform, DOMAIN, {}, config))
|
||||||
|
|
||||||
|
return True
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"domain": "zoneminder_alarm",
|
||||||
|
"name": "Zoneminder Alarm",
|
||||||
|
"documentation": "",
|
||||||
|
"dependencies": [],
|
||||||
|
"codeowners": [],
|
||||||
|
"requirements": [
|
||||||
|
"zm-py"
|
||||||
|
],
|
||||||
|
"iot_class": "local_polling",
|
||||||
|
"version": "0.1.0"
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
"""Support for ZoneMinder switches."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from zoneminder.monitor import Monitor
|
||||||
|
from zoneminder.zm import ZoneMinder
|
||||||
|
|
||||||
|
from homeassistant.components.sensor import (
|
||||||
|
SensorEntity,
|
||||||
|
)
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||||
|
from homeassistant.components.zoneminder import DOMAIN as ZONEMINDER_DOMAIN
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def setup_platform(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config: ConfigType, # pylint: disable=unused-argument
|
||||||
|
add_entities: AddEntitiesCallback,
|
||||||
|
discovery_info: DiscoveryInfoType | None = None, # pylint: disable=unused-argument
|
||||||
|
) -> None:
|
||||||
|
"""Set up the ZoneMinder switch platform."""
|
||||||
|
sensors = []
|
||||||
|
for zm_client in hass.data[ZONEMINDER_DOMAIN].values():
|
||||||
|
if not (monitors := zm_client.get_monitors()):
|
||||||
|
_LOGGER.warning("Could not fetch monitors from ZoneMinder")
|
||||||
|
return
|
||||||
|
|
||||||
|
for monitor in monitors:
|
||||||
|
sensors.append(ZMSensorAlarm(zm_client, monitor))
|
||||||
|
add_entities(sensors)
|
||||||
|
|
||||||
|
|
||||||
|
class ZMSensorAlarm(SensorEntity):
|
||||||
|
"""Representation of a Sensor."""
|
||||||
|
|
||||||
|
def __init__(self, client: ZoneMinder, monitor: Monitor):
|
||||||
|
"""Initialize the switch."""
|
||||||
|
self._client = client
|
||||||
|
self._monitor = monitor
|
||||||
|
self._state = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
"""Return the name of the switch."""
|
||||||
|
return f"{self._monitor.name} Alarm Status"
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
"""Update the switch value."""
|
||||||
|
data = self._get_data("status")
|
||||||
|
state = int(data["status"])
|
||||||
|
if state == 0:
|
||||||
|
self._state = "Normal"
|
||||||
|
if state == 1:
|
||||||
|
self._state = "Warnung"
|
||||||
|
if state == 2:
|
||||||
|
self._state = "Alarm"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def native_value(self):
|
||||||
|
return self._state
|
||||||
|
|
||||||
|
def _get_data(self, command: str):
|
||||||
|
return self._client.get_state(
|
||||||
|
f"api/monitors/alarm/id:{self._monitor.id}/command:{command}.json"
|
||||||
|
)
|
|
@ -0,0 +1,15 @@
|
||||||
|
trigger_alarm_state:
|
||||||
|
description: Trigger alarm in Zoneminder for monitor id.
|
||||||
|
fields:
|
||||||
|
name:
|
||||||
|
description: Zoneminder hostname
|
||||||
|
required: true
|
||||||
|
example: default
|
||||||
|
selector:
|
||||||
|
text:
|
||||||
|
id:
|
||||||
|
description: Monitor ID
|
||||||
|
required: true
|
||||||
|
example: 1
|
||||||
|
selector:
|
||||||
|
text:
|
|
@ -0,0 +1,79 @@
|
||||||
|
"""Support for ZoneMinder switches."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from zoneminder.monitor import Monitor
|
||||||
|
from zoneminder.zm import ZoneMinder
|
||||||
|
|
||||||
|
from homeassistant.components.switch import SwitchEntity
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||||
|
from homeassistant.components.zoneminder import DOMAIN as ZONEMINDER_DOMAIN
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def setup_platform(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config: ConfigType, # pylint: disable=unused-argument
|
||||||
|
add_entities: AddEntitiesCallback,
|
||||||
|
discovery_info: DiscoveryInfoType | None = None, # pylint: disable=unused-argument
|
||||||
|
) -> None:
|
||||||
|
"""Set up the ZoneMinder switch platform."""
|
||||||
|
switches = []
|
||||||
|
for zm_client in hass.data[ZONEMINDER_DOMAIN].values():
|
||||||
|
if not (monitors := zm_client.get_monitors()):
|
||||||
|
_LOGGER.warning("Could not fetch monitors from ZoneMinder")
|
||||||
|
return
|
||||||
|
|
||||||
|
for monitor in monitors:
|
||||||
|
switches.append(ZMSwitchMonitors(zm_client, monitor))
|
||||||
|
add_entities(switches)
|
||||||
|
|
||||||
|
|
||||||
|
class ZMSwitchMonitors(SwitchEntity):
|
||||||
|
"""Representation of a ZoneMinder switch."""
|
||||||
|
|
||||||
|
icon = "mdi:alarm-bell"
|
||||||
|
|
||||||
|
def __init__(self, client: ZoneMinder, monitor: Monitor):
|
||||||
|
"""Initialize the switch."""
|
||||||
|
self._client = client
|
||||||
|
self._monitor = monitor
|
||||||
|
self._state = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
"""Return the name of the switch."""
|
||||||
|
return f"{self._monitor.name} Alarm Status"
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
"""Update the switch value."""
|
||||||
|
data = self._get_data("status")
|
||||||
|
self._state = int(data["status"]) > 0
|
||||||
|
|
||||||
|
def _get_data(self, command: str):
|
||||||
|
return self._client.get_state(
|
||||||
|
f"api/monitors/alarm/id:{self._monitor.id}/command:{command}.json"
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_on(self):
|
||||||
|
"""Return True if entity is on."""
|
||||||
|
return self._state
|
||||||
|
|
||||||
|
def turn_on(self, **kwargs):
|
||||||
|
"""Turn the entity on."""
|
||||||
|
result = self._get_data("on")
|
||||||
|
data = self._get_data("status")
|
||||||
|
self._state = int(data["status"]) > 0
|
||||||
|
return result
|
||||||
|
|
||||||
|
def turn_off(self, **kwargs):
|
||||||
|
"""Turn the entity off."""
|
||||||
|
result = self._get_data("off")
|
||||||
|
data = self._get_data("status")
|
||||||
|
self._state = int(data["status"]) > 0
|
||||||
|
return result
|
Loading…
Reference in New Issue