initial commit

This commit is contained in:
Patrick Neff 2022-01-24 22:35:55 +01:00
commit 97699c6c2d
6 changed files with 283 additions and 0 deletions

6
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,6 @@
{
"python.formatting.provider": "black",
"python.linting.flake8Enabled": false,
"python.linting.pylintEnabled": true,
"python.linting.enabled": true
}

View File

@ -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

View File

@ -0,0 +1,12 @@
{
"domain": "zoneminder_alarm",
"name": "Zoneminder Alarm",
"documentation": "",
"dependencies": [],
"codeowners": [],
"requirements": [
"zm-py"
],
"iot_class": "local_polling",
"version": "0.1.0"
}

View File

@ -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"
)

View File

@ -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:

View File

@ -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