Skip to content

Commit e006e0d

Browse files
Revert zoneminder config flow (home-assistant#41395)
1 parent 0f3489f commit e006e0d

22 files changed

+119
-1238
lines changed

.coveragerc

+1
Original file line numberDiff line numberDiff line change
@@ -1053,6 +1053,7 @@ omit =
10531053
homeassistant/components/zhong_hong/climate.py
10541054
homeassistant/components/xbee/*
10551055
homeassistant/components/ziggo_mediabox_xl/media_player.py
1056+
homeassistant/components/zoneminder/*
10561057
homeassistant/components/supla/*
10571058
homeassistant/components/zwave/util.py
10581059

CODEOWNERS

+1-1
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,7 @@ homeassistant/components/zerproc/* @emlove
514514
homeassistant/components/zha/* @dmulcahey @adminiuga
515515
homeassistant/components/zodiac/* @JulienTant
516516
homeassistant/components/zone/* @home-assistant/core
517-
homeassistant/components/zoneminder/* @rohankapoorcom @vangorra
517+
homeassistant/components/zoneminder/* @rohankapoorcom
518518
homeassistant/components/zwave/* @home-assistant/z-wave
519519

520520
# Individual files

homeassistant/components/zoneminder/__init__.py

+55-127
Original file line numberDiff line numberDiff line change
@@ -2,169 +2,97 @@
22
import logging
33

44
import voluptuous as vol
5+
from zoneminder.zm import ZoneMinder
56

6-
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN
7-
from homeassistant.components.camera import DOMAIN as CAMERA_DOMAIN
8-
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
9-
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
10-
import homeassistant.config_entries as config_entries
11-
from homeassistant.config_entries import ConfigEntry
127
from homeassistant.const import (
138
ATTR_ID,
149
ATTR_NAME,
1510
CONF_HOST,
1611
CONF_PASSWORD,
1712
CONF_PATH,
18-
CONF_PLATFORM,
19-
CONF_SOURCE,
2013
CONF_SSL,
2114
CONF_USERNAME,
2215
CONF_VERIFY_SSL,
2316
)
24-
from homeassistant.core import HomeAssistant, callback
25-
from homeassistant.exceptions import ConfigEntryNotReady
26-
from homeassistant.helpers import config_validation as cv
27-
28-
from . import const
29-
from .common import (
30-
ClientAvailabilityResult,
31-
async_test_client_availability,
32-
create_client_from_config,
33-
del_client_from_data,
34-
get_client_from_data,
35-
is_client_in_data,
36-
set_client_to_data,
37-
set_platform_configs,
38-
)
17+
import homeassistant.helpers.config_validation as cv
18+
from homeassistant.helpers.discovery import async_load_platform
3919

4020
_LOGGER = logging.getLogger(__name__)
41-
PLATFORM_DOMAINS = tuple(
42-
[BINARY_SENSOR_DOMAIN, CAMERA_DOMAIN, SENSOR_DOMAIN, SWITCH_DOMAIN]
43-
)
21+
22+
CONF_PATH_ZMS = "path_zms"
23+
24+
DEFAULT_PATH = "/zm/"
25+
DEFAULT_PATH_ZMS = "/zm/cgi-bin/nph-zms"
26+
DEFAULT_SSL = False
27+
DEFAULT_TIMEOUT = 10
28+
DEFAULT_VERIFY_SSL = True
29+
DOMAIN = "zoneminder"
4430

4531
HOST_CONFIG_SCHEMA = vol.Schema(
4632
{
4733
vol.Required(CONF_HOST): cv.string,
4834
vol.Optional(CONF_PASSWORD): cv.string,
49-
vol.Optional(CONF_PATH, default=const.DEFAULT_PATH): cv.string,
50-
vol.Optional(const.CONF_PATH_ZMS, default=const.DEFAULT_PATH_ZMS): cv.string,
51-
vol.Optional(CONF_SSL, default=const.DEFAULT_SSL): cv.boolean,
35+
vol.Optional(CONF_PATH, default=DEFAULT_PATH): cv.string,
36+
vol.Optional(CONF_PATH_ZMS, default=DEFAULT_PATH_ZMS): cv.string,
37+
vol.Optional(CONF_SSL, default=DEFAULT_SSL): cv.boolean,
5238
vol.Optional(CONF_USERNAME): cv.string,
53-
vol.Optional(CONF_VERIFY_SSL, default=const.DEFAULT_VERIFY_SSL): cv.boolean,
39+
vol.Optional(CONF_VERIFY_SSL, default=DEFAULT_VERIFY_SSL): cv.boolean,
5440
}
5541
)
5642

57-
CONFIG_SCHEMA = vol.All(
58-
cv.deprecated(const.DOMAIN, invalidation_version="0.118"),
59-
vol.Schema(
60-
{const.DOMAIN: vol.All(cv.ensure_list, [HOST_CONFIG_SCHEMA])},
61-
extra=vol.ALLOW_EXTRA,
62-
),
43+
CONFIG_SCHEMA = vol.Schema(
44+
{DOMAIN: vol.All(cv.ensure_list, [HOST_CONFIG_SCHEMA])}, extra=vol.ALLOW_EXTRA
6345
)
6446

47+
SERVICE_SET_RUN_STATE = "set_run_state"
6548
SET_RUN_STATE_SCHEMA = vol.Schema(
6649
{vol.Required(ATTR_ID): cv.string, vol.Required(ATTR_NAME): cv.string}
6750
)
6851

6952

70-
async def async_setup(hass: HomeAssistant, base_config: dict):
53+
def setup(hass, config):
7154
"""Set up the ZoneMinder component."""
7255

73-
# Collect the platform specific configs. It's necessary to collect these configs
74-
# here instead of the platform's setup_platform function because the invocation order
75-
# of setup_platform and async_setup_entry is not consistent.
76-
set_platform_configs(
77-
hass,
78-
SENSOR_DOMAIN,
79-
[
80-
platform_config
81-
for platform_config in base_config.get(SENSOR_DOMAIN, [])
82-
if platform_config[CONF_PLATFORM] == const.DOMAIN
83-
],
84-
)
85-
set_platform_configs(
86-
hass,
87-
SWITCH_DOMAIN,
88-
[
89-
platform_config
90-
for platform_config in base_config.get(SWITCH_DOMAIN, [])
91-
if platform_config[CONF_PLATFORM] == const.DOMAIN
92-
],
93-
)
94-
95-
config = base_config.get(const.DOMAIN)
96-
97-
if not config:
98-
return True
99-
100-
for config_item in config:
101-
hass.async_create_task(
102-
hass.config_entries.flow.async_init(
103-
const.DOMAIN,
104-
context={CONF_SOURCE: config_entries.SOURCE_IMPORT},
105-
data=config_item,
106-
)
107-
)
108-
109-
return True
110-
111-
112-
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
113-
"""Set up Zoneminder config entry."""
114-
zm_client = create_client_from_config(config_entry.data)
56+
hass.data[DOMAIN] = {}
11557

116-
result = await async_test_client_availability(hass, zm_client)
117-
if result != ClientAvailabilityResult.AVAILABLE:
118-
raise ConfigEntryNotReady
58+
success = True
11959

120-
set_client_to_data(hass, config_entry.unique_id, zm_client)
60+
for conf in config[DOMAIN]:
61+
protocol = "https" if conf[CONF_SSL] else "http"
12162

122-
for platform_domain in PLATFORM_DOMAINS:
123-
hass.async_create_task(
124-
hass.config_entries.async_forward_entry_setup(config_entry, platform_domain)
63+
host_name = conf[CONF_HOST]
64+
server_origin = f"{protocol}://{host_name}"
65+
zm_client = ZoneMinder(
66+
server_origin,
67+
conf.get(CONF_USERNAME),
68+
conf.get(CONF_PASSWORD),
69+
conf.get(CONF_PATH),
70+
conf.get(CONF_PATH_ZMS),
71+
conf.get(CONF_VERIFY_SSL),
12572
)
126-
127-
if not hass.services.has_service(const.DOMAIN, const.SERVICE_SET_RUN_STATE):
128-
129-
@callback
130-
def set_active_state(call):
131-
"""Set the ZoneMinder run state to the given state name."""
132-
zm_id = call.data[ATTR_ID]
133-
state_name = call.data[ATTR_NAME]
134-
if not is_client_in_data(hass, zm_id):
135-
_LOGGER.error("Invalid ZoneMinder host provided: %s", zm_id)
136-
return
137-
138-
if not get_client_from_data(hass, zm_id).set_active_state(state_name):
139-
_LOGGER.error(
140-
"Unable to change ZoneMinder state. Host: %s, state: %s",
141-
zm_id,
142-
state_name,
143-
)
144-
145-
hass.services.async_register(
146-
const.DOMAIN,
147-
const.SERVICE_SET_RUN_STATE,
148-
set_active_state,
149-
schema=SET_RUN_STATE_SCHEMA,
150-
)
151-
152-
return True
153-
154-
155-
async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
156-
"""Unload Zoneminder config entry."""
157-
for platform_domain in PLATFORM_DOMAINS:
158-
hass.async_create_task(
159-
hass.config_entries.async_forward_entry_unload(
160-
config_entry, platform_domain
73+
hass.data[DOMAIN][host_name] = zm_client
74+
75+
success = zm_client.login() and success
76+
77+
def set_active_state(call):
78+
"""Set the ZoneMinder run state to the given state name."""
79+
zm_id = call.data[ATTR_ID]
80+
state_name = call.data[ATTR_NAME]
81+
if zm_id not in hass.data[DOMAIN]:
82+
_LOGGER.error("Invalid ZoneMinder host provided: %s", zm_id)
83+
if not hass.data[DOMAIN][zm_id].set_active_state(state_name):
84+
_LOGGER.error(
85+
"Unable to change ZoneMinder state. Host: %s, state: %s",
86+
zm_id,
87+
state_name,
16188
)
162-
)
16389

164-
# If this is the last config to exist, remove the service too.
165-
if len(hass.config_entries.async_entries(const.DOMAIN)) <= 1:
166-
hass.services.async_remove(const.DOMAIN, const.SERVICE_SET_RUN_STATE)
90+
hass.services.register(
91+
DOMAIN, SERVICE_SET_RUN_STATE, set_active_state, schema=SET_RUN_STATE_SCHEMA
92+
)
16793

168-
del_client_from_data(hass, config_entry.unique_id)
94+
hass.async_create_task(
95+
async_load_platform(hass, "binary_sensor", DOMAIN, {}, config)
96+
)
16997

170-
return True
98+
return success

homeassistant/components/zoneminder/binary_sensor.py

+10-24
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,29 @@
11
"""Support for ZoneMinder binary sensors."""
2-
from typing import Callable, List, Optional
3-
4-
from zoneminder.zm import ZoneMinder
5-
62
from homeassistant.components.binary_sensor import (
73
DEVICE_CLASS_CONNECTIVITY,
84
BinarySensorEntity,
95
)
10-
from homeassistant.config_entries import ConfigEntry
11-
from homeassistant.core import HomeAssistant
12-
from homeassistant.helpers.entity import Entity
136

14-
from .common import get_client_from_data
7+
from . import DOMAIN as ZONEMINDER_DOMAIN
158

169

17-
async def async_setup_entry(
18-
hass: HomeAssistant,
19-
config_entry: ConfigEntry,
20-
async_add_entities: Callable[[List[Entity], Optional[bool]], None],
21-
) -> None:
22-
"""Set up the sensor config entry."""
23-
zm_client = get_client_from_data(hass, config_entry.unique_id)
24-
async_add_entities([ZMAvailabilitySensor(zm_client, config_entry)])
10+
async def async_setup_platform(hass, config, add_entities, discovery_info=None):
11+
"""Set up the ZoneMinder binary sensor platform."""
12+
sensors = []
13+
for host_name, zm_client in hass.data[ZONEMINDER_DOMAIN].items():
14+
sensors.append(ZMAvailabilitySensor(host_name, zm_client))
15+
add_entities(sensors)
16+
return True
2517

2618

2719
class ZMAvailabilitySensor(BinarySensorEntity):
2820
"""Representation of the availability of ZoneMinder as a binary sensor."""
2921

30-
def __init__(self, client: ZoneMinder, config_entry: ConfigEntry):
22+
def __init__(self, host_name, client):
3123
"""Initialize availability sensor."""
3224
self._state = None
33-
self._name = config_entry.unique_id
25+
self._name = host_name
3426
self._client = client
35-
self._config_entry = config_entry
36-
37-
@property
38-
def unique_id(self) -> Optional[str]:
39-
"""Return a unique ID."""
40-
return f"{self._config_entry.unique_id}_availability"
4127

4228
@property
4329
def name(self):

homeassistant/components/zoneminder/camera.py

+12-29
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,39 @@
11
"""Support for ZoneMinder camera streaming."""
22
import logging
3-
from typing import Callable, List, Optional
4-
5-
from zoneminder.monitor import Monitor
63

74
from homeassistant.components.mjpeg.camera import (
85
CONF_MJPEG_URL,
96
CONF_STILL_IMAGE_URL,
107
MjpegCamera,
118
filter_urllib3_logging,
129
)
13-
from homeassistant.config_entries import ConfigEntry
1410
from homeassistant.const import CONF_NAME, CONF_VERIFY_SSL
15-
from homeassistant.core import HomeAssistant
16-
from homeassistant.helpers.entity import Entity
1711

18-
from .common import get_client_from_data
12+
from . import DOMAIN as ZONEMINDER_DOMAIN
1913

2014
_LOGGER = logging.getLogger(__name__)
2115

2216

2317
def setup_platform(hass, config, add_entities, discovery_info=None):
2418
"""Set up the ZoneMinder cameras."""
2519
filter_urllib3_logging()
20+
cameras = []
21+
for zm_client in hass.data[ZONEMINDER_DOMAIN].values():
22+
monitors = zm_client.get_monitors()
23+
if not monitors:
24+
_LOGGER.warning("Could not fetch monitors from ZoneMinder host: %s")
25+
return
2626

27-
28-
async def async_setup_entry(
29-
hass: HomeAssistant,
30-
config_entry: ConfigEntry,
31-
async_add_entities: Callable[[List[Entity], Optional[bool]], None],
32-
) -> None:
33-
"""Set up the sensor config entry."""
34-
zm_client = get_client_from_data(hass, config_entry.unique_id)
35-
36-
async_add_entities(
37-
[
38-
ZoneMinderCamera(monitor, zm_client.verify_ssl, config_entry)
39-
for monitor in await hass.async_add_job(zm_client.get_monitors)
40-
]
41-
)
27+
for monitor in monitors:
28+
_LOGGER.info("Initializing camera %s", monitor.id)
29+
cameras.append(ZoneMinderCamera(monitor, zm_client.verify_ssl))
30+
add_entities(cameras)
4231

4332

4433
class ZoneMinderCamera(MjpegCamera):
4534
"""Representation of a ZoneMinder Monitor Stream."""
4635

47-
def __init__(self, monitor: Monitor, verify_ssl: bool, config_entry: ConfigEntry):
36+
def __init__(self, monitor, verify_ssl):
4837
"""Initialize as a subclass of MjpegCamera."""
4938
device_info = {
5039
CONF_NAME: monitor.name,
@@ -56,12 +45,6 @@ def __init__(self, monitor: Monitor, verify_ssl: bool, config_entry: ConfigEntry
5645
self._is_recording = None
5746
self._is_available = None
5847
self._monitor = monitor
59-
self._config_entry = config_entry
60-
61-
@property
62-
def unique_id(self) -> Optional[str]:
63-
"""Return a unique ID."""
64-
return f"{self._config_entry.unique_id}_{self._monitor.id}_camera"
6548

6649
@property
6750
def should_poll(self):

0 commit comments

Comments
 (0)