1 """Support for Hikvision event stream events represented as binary sensors."""
3 from __future__
import annotations
5 from datetime
import timedelta
8 from pyhik.hikvision
import HikCamera
9 import voluptuous
as vol
12 PLATFORM_SCHEMA
as BINARY_SENSOR_PLATFORM_SCHEMA,
13 BinarySensorDeviceClass,
26 EVENT_HOMEASSISTANT_START,
27 EVENT_HOMEASSISTANT_STOP,
36 _LOGGER = logging.getLogger(__name__)
38 CONF_IGNORED =
"ignored"
41 DEFAULT_IGNORED =
False
47 "Motion": BinarySensorDeviceClass.MOTION,
48 "Line Crossing": BinarySensorDeviceClass.MOTION,
49 "Field Detection": BinarySensorDeviceClass.MOTION,
50 "Tamper Detection": BinarySensorDeviceClass.MOTION,
51 "Shelter Alarm":
None,
54 "Net Interface Broken": BinarySensorDeviceClass.CONNECTIVITY,
55 "IP Conflict": BinarySensorDeviceClass.CONNECTIVITY,
56 "Illegal Access":
None,
57 "Video Mismatch":
None,
59 "PIR Alarm": BinarySensorDeviceClass.MOTION,
60 "Face Detection": BinarySensorDeviceClass.MOTION,
61 "Scene Change Detection": BinarySensorDeviceClass.MOTION,
63 "Unattended Baggage": BinarySensorDeviceClass.MOTION,
64 "Attended Baggage": BinarySensorDeviceClass.MOTION,
65 "Recording Failure":
None,
66 "Exiting Region": BinarySensorDeviceClass.MOTION,
67 "Entering Region": BinarySensorDeviceClass.MOTION,
70 CUSTOMIZE_SCHEMA = vol.Schema(
72 vol.Optional(CONF_IGNORED, default=DEFAULT_IGNORED): cv.boolean,
73 vol.Optional(CONF_DELAY, default=DEFAULT_DELAY): cv.positive_int,
77 PLATFORM_SCHEMA = BINARY_SENSOR_PLATFORM_SCHEMA.extend(
79 vol.Optional(CONF_NAME): cv.string,
80 vol.Required(CONF_HOST): cv.string,
81 vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
82 vol.Optional(CONF_SSL, default=
False): cv.boolean,
83 vol.Required(CONF_USERNAME): cv.string,
84 vol.Required(CONF_PASSWORD): cv.string,
85 vol.Optional(CONF_CUSTOMIZE, default={}): vol.Schema(
86 {cv.string: CUSTOMIZE_SCHEMA}
95 add_entities: AddEntitiesCallback,
96 discovery_info: DiscoveryInfoType |
None =
None,
98 """Set up the Hikvision binary sensor devices."""
99 name = config.get(CONF_NAME)
100 host = config[CONF_HOST]
101 port = config[CONF_PORT]
102 username = config[CONF_USERNAME]
103 password = config[CONF_PASSWORD]
105 customize = config[CONF_CUSTOMIZE]
107 protocol =
"https" if config[CONF_SSL]
else "http"
109 url = f
"{protocol}://{host}"
111 data =
HikvisionData(hass, url, port, name, username, password)
113 if data.sensors
is None:
114 _LOGGER.error(
"Hikvision event stream has no data, unable to set up")
119 for sensor, channel_list
in data.sensors.items():
120 for channel
in channel_list:
122 if data.type ==
"NVR":
123 sensor_name = f
"{sensor.replace(' ', '_')}_{channel[1]}"
125 sensor_name = sensor.replace(
" ",
"_")
127 custom = customize.get(sensor_name.lower(), {})
128 ignore = custom.get(CONF_IGNORED)
129 delay = custom.get(CONF_DELAY)
132 "Entity: %s - %s, Options - Ignore: %s, Delay: %s",
147 """Hikvision device event stream object."""
149 def __init__(self, hass, url, port, name, username, password):
150 """Initialize the data object."""
160 if self.
_name_name
is None:
163 hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, self.
stop_hikstop_hik)
164 hass.bus.listen_once(EVENT_HOMEASSISTANT_START, self.
start_hikstart_hik)
167 """Shutdown Hikvision subscriptions and subscription thread on exit."""
168 self.
camdatacamdata.disconnect()
171 """Start Hikvision event stream thread."""
172 self.
camdatacamdata.start_stream()
176 """Return list of available sensors and their states."""
177 return self.
camdatacamdata.current_event_states
181 """Return device id."""
182 return self.
camdatacamdata.get_id
186 """Return device name."""
187 return self.
_name_name
191 """Return device type."""
192 return self.
camdatacamdata.get_type
195 """Return attribute list for sensor/channel."""
196 return self.
camdatacamdata.fetch_attributes(sensor, channel)
200 """Representation of a Hikvision binary sensor."""
202 _attr_should_poll =
False
204 def __init__(self, hass, sensor, channel, cam, delay):
205 """Initialize the binary_sensor."""
211 if self.
_cam_cam.type ==
"NVR":
212 self.
_name_name = f
"{self._cam.name} {sensor} {channel}"
214 self.
_name_name = f
"{self._cam.name} {sensor}"
216 self.
_id_id = f
"{self._cam.cam_id}.{sensor}.{channel}"
229 """Extract sensor state."""
233 """Extract sensor last update time."""
238 """Return the name of the Hikvision sensor."""
239 return self.
_name_name
243 """Return a unique ID."""
248 """Return true if sensor is on."""
253 """Return the class of this sensor, from DEVICE_CLASSES."""
255 return DEVICE_CLASS_MAP[self.
_sensor_sensor]
262 """Return the state attributes."""
265 if self.
_delay_delay != 0:
266 attr[ATTR_DELAY] = self.
_delay_delay
271 """Update the sensor's state, if needed."""
272 _LOGGER.debug(
"Callback signal from: %s", msg)
276 def _delay_update(now):
277 """Timer callback for sensor update."""
279 "%s Called delayed (%ssec) update", self.
_name_name, self.
_delay_delay
284 if self.
_timer_timer
is not None:
294 if self.
_timer_timer
is not None:
def _sensor_last_update(self)
def extra_state_attributes(self)
def __init__(self, hass, sensor, channel, cam, delay)
def _update_callback(self, msg)
def __init__(self, hass, url, port, name, username, password)
def get_attributes(self, sensor, channel)
def stop_hik(self, event)
def start_hik(self, event)
None schedule_update_ha_state(self, bool force_refresh=False)
None add_entities(AsusWrtRouter router, AddEntitiesCallback async_add_entities, set[str] tracked)
None setup_platform(HomeAssistant hass, ConfigType config, AddEntitiesCallback add_entities, DiscoveryInfoType|None discovery_info=None)