Skip to content

Commit

Permalink
Fix cycling import bug (#6)
Browse files Browse the repository at this point in the history
  • Loading branch information
Limych committed Sep 12, 2020
1 parent 746d1d3 commit 2fbebcb
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 137 deletions.
8 changes: 4 additions & 4 deletions custom_components/beward/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@
from homeassistant.helpers.storage import STORAGE_DIR
from homeassistant.util import slugify

from .binary_sensor import BINARY_SENSORS
from .camera import CAMERAS
from .const import (
CONF_STREAM,
ALARMS_TO_EVENTS,
Expand All @@ -48,14 +46,16 @@
SUPPORT_LIB_URL,
DEVICE_CHECK_INTERVAL,
ATTR_DEVICE_ID,
CAMERAS,
BINARY_SENSORS,
SENSORS,
)
from .sensor import SENSORS

_LOGGER = logging.getLogger(__name__)

# Base component constants
DOMAIN = "beward"
VERSION = '1.1.5'
VERSION = "1.1.5"
ISSUE_URL = "https://github.com/Limych/ha-beward/issues"
ATTRIBUTION = "Data provided by Beward device."

Expand Down
50 changes: 15 additions & 35 deletions custom_components/beward/binary_sensor.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Binary sensor platform for Beward devices."""

import logging
from typing import Dict
from typing import Dict, Optional, Any

import beward

Expand All @@ -11,34 +11,19 @@
from homeassistant.components.binary_sensor import (
BinarySensorDevice as BinarySensorEntity,
)
from homeassistant.components.binary_sensor import (
DEVICE_CLASS_MOTION,
DEVICE_CLASS_CONNECTIVITY,
)
from homeassistant.const import CONF_NAME, CONF_BINARY_SENSORS
from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect

from . import DOMAIN
from .const import (
EVENT_DING,
EVENT_MOTION,
EVENT_ONLINE,
CAT_DOORBELL,
CAT_CAMERA,
)
from .const import EVENT_ONLINE, CAT_DOORBELL, CAT_CAMERA, BINARY_SENSORS

_LOGGER = logging.getLogger(__name__)

# Sensor types: Name, category, class
BINARY_SENSORS: Dict[str, list] = {
EVENT_DING: ["Ding", [CAT_DOORBELL], None],
EVENT_MOTION: ["Motion", [CAT_DOORBELL, CAT_CAMERA], DEVICE_CLASS_MOTION],
EVENT_ONLINE: ["Online", [CAT_DOORBELL, CAT_CAMERA], DEVICE_CLASS_CONNECTIVITY],
}


async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
async def async_setup_platform(
hass, config, async_add_entities, discovery_info=None
) -> None:
"""Set up a binary sensors for a Beward device."""
if discovery_info is None:
return
Expand All @@ -53,7 +38,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=

sensors = []
for sensor_type in discovery_info[CONF_BINARY_SENSORS]:
if category in BINARY_SENSORS.get(sensor_type)[1]:
if category in BINARY_SENSORS[sensor_type][1]:
sensors.append(BewardBinarySensor(controller, sensor_type))

async_add_entities(sensors, True)
Expand All @@ -77,12 +62,7 @@ def __init__(self, controller, sensor_type: str):
self._unique_id = f"{self._controller.unique_id}-{self._sensor_type}"

@property
def name(self):
"""Return the name of the sensor."""
return self._name

@property
def should_poll(self):
def should_poll(self) -> bool:
"""Return True if entity has to be polled for state."""
return False

Expand All @@ -92,31 +72,31 @@ def available(self) -> bool:
return self._sensor_type == EVENT_ONLINE or self._controller.available

@property
def is_on(self):
def is_on(self) -> Optional[bool]:
"""Return True if the binary sensor is on."""
return self._state

@property
def device_class(self):
def device_class(self) -> Optional[str]:
"""Return the class of the binary sensor."""
return self._device_class

@property
def unique_id(self):
def unique_id(self) -> Optional[str]:
"""Return a unique ID."""
return self._unique_id

@property
def device_state_attributes(self):
def device_state_attributes(self) -> Optional[Dict[str, Any]]:
"""Return the state attributes."""
return self._controller.device_state_attributes

async def async_update(self):
async def async_update(self) -> None:
"""Get the latest data and updates the state."""
self._update_callback(update_ha_state=False)

@callback
def _update_callback(self, update_ha_state=True):
def _update_callback(self, update_ha_state=True) -> None:
"""Get the latest data and updates the state."""
state = (
self._controller.available
Expand All @@ -131,13 +111,13 @@ def _update_callback(self, update_ha_state=True):
if update_ha_state:
self.async_schedule_update_ha_state()

async def async_added_to_hass(self):
async def async_added_to_hass(self) -> None:
"""Register callbacks."""
self._unsub_dispatcher = async_dispatcher_connect(
self.hass, self._controller.service_signal("update"), self._update_callback,
)

async def async_will_remove_from_hass(self):
async def async_will_remove_from_hass(self) -> None:
"""Disconnect from update signal."""
if self._unsub_dispatcher is not None:
self._unsub_dispatcher()
49 changes: 16 additions & 33 deletions custom_components/beward/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@
import datetime
import logging
from asyncio import run_coroutine_threadsafe
from typing import Dict
from typing import Dict, Optional, Any

import aiohttp
import async_timeout
import beward
from aiohttp.abc import StreamResponse
from haffmpeg.camera import CameraMjpeg
from homeassistant.components.camera import Camera, SUPPORT_STREAM
from homeassistant.components.ffmpeg import DATA_FFMPEG
Expand All @@ -27,39 +28,21 @@
from . import DOMAIN
from .const import (
CONF_FFMPEG_ARGUMENTS,
EVENT_MOTION,
EVENT_DING,
CAT_DOORBELL,
CAT_CAMERA,
CONF_CAMERAS,
CAMERAS,
CAMERA_LIVE,
CAMERA_NAME_LIVE,
)

_LOGGER = logging.getLogger(__name__)

_UPDATE_INTERVAL_LIVE = datetime.timedelta(seconds=1)
_SESSION_TIMEOUT = 10 # seconds

CAMERA_LIVE = "live"
CAMERA_LAST_MOTION = "last_motion"
CAMERA_LAST_DING = "last_ding"

CAMERA_NAME_LIVE = "{} Live"
CAMERA_NAME_LAST_MOTION = "{} Last Motion"
CAMERA_NAME_LAST_DING = "{} Last Ding"

# Camera types are defined like: name template, device class, device event
CAMERAS: Dict[str, list] = {
CAMERA_LIVE: [CAMERA_NAME_LIVE, [CAT_DOORBELL, CAT_CAMERA], None],
CAMERA_LAST_MOTION: [
CAMERA_NAME_LAST_MOTION,
[CAT_DOORBELL, CAT_CAMERA],
EVENT_MOTION,
],
CAMERA_LAST_DING: [CAMERA_NAME_LAST_DING, [CAT_DOORBELL], EVENT_DING],
}


def setup_platform(hass, config, add_entities, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None) -> None:
"""Set up a cameras for a Beward device."""
if discovery_info is None:
return
Expand All @@ -74,14 +57,14 @@ def setup_platform(hass, config, add_entities, discovery_info=None):

cameras = []
for camera_type in discovery_info[CONF_CAMERAS]:
if category in CAMERAS.get(camera_type)[1]:
if category in CAMERAS[camera_type][1]:
if camera_type == CAMERA_LIVE:
cameras.append(BewardCamera(controller, config))
else:
cameras.append(
LocalFile(
CAMERAS.get(camera_type)[0].format(name),
controller.history_image_path(CAMERAS.get(camera_type)[2]),
CAMERAS[camera_type][0].format(name),
controller.history_image_path(CAMERAS[camera_type][2]),
)
)

Expand All @@ -107,19 +90,19 @@ def __init__(self, controller, config):
self._ffmpeg_input = "-rtsp_transport tcp -i " + self._stream_url
self._ffmpeg_arguments = config.get(CONF_FFMPEG_ARGUMENTS)

async def stream_source(self):
async def stream_source(self) -> Optional[str]:
"""Return the stream source."""
return self._stream_url

@property
def supported_features(self):
def supported_features(self) -> Optional[int]:
"""Return supported features."""
if self._stream_url:
return SUPPORT_STREAM
return 0

@property
def name(self):
def name(self) -> Optional[str]:
"""Get the name of the camera."""
return self._name

Expand All @@ -129,17 +112,17 @@ def available(self) -> bool:
return self._controller.available

@property
def device_state_attributes(self):
def device_state_attributes(self) -> Optional[Dict[str, Any]]:
"""Return the state attributes."""
return self._controller.device_state_attributes

def camera_image(self):
def camera_image(self) -> bytes:
"""Return camera image."""
return run_coroutine_threadsafe(
self.async_camera_image(), self.hass.loop
).result()

async def async_camera_image(self):
async def async_camera_image(self) -> bytes:
"""Pull a still image from the camera."""
now = datetime.datetime.now()

Expand All @@ -161,7 +144,7 @@ async def async_camera_image(self):
_LOGGER.error("Error getting camera image: %s", error)
return self._last_image

async def handle_async_mjpeg_stream(self, request):
async def handle_async_mjpeg_stream(self, request) -> Optional[StreamResponse]:
"""Generate an HTTP MJPEG stream from the camera."""
if not self._stream_url:
return None
Expand Down
53 changes: 53 additions & 0 deletions custom_components/beward/const.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
"""Constants for Beward component."""
from datetime import timedelta
from typing import Dict

from beward.const import ALARM_MOTION, ALARM_SENSOR
from homeassistant.components.binary_sensor import (
DEVICE_CLASS_MOTION,
DEVICE_CLASS_CONNECTIVITY,
)
from homeassistant.const import DEVICE_CLASS_TIMESTAMP

SUPPORT_LIB_URL = "https://github.com/Limych/py-beward/issues/new/choose"

Expand All @@ -26,3 +32,50 @@
CAT_CAMERA = "camera"

DEVICE_CHECK_INTERVAL = timedelta(seconds=15)

CAMERA_LIVE = "live"
CAMERA_LAST_MOTION = "last_motion"
CAMERA_LAST_DING = "last_ding"

CAMERA_NAME_LIVE = "{} Live"
CAMERA_NAME_LAST_MOTION = "{} Last Motion"
CAMERA_NAME_LAST_DING = "{} Last Ding"

SENSOR_LAST_ACTIVITY = "last_activity"
SENSOR_LAST_MOTION = "last_motion"
SENSOR_LAST_DING = "last_ding"

# Camera types are defined like: name template, device class, device event
CAMERAS: Dict[str, list] = {
CAMERA_LIVE: [CAMERA_NAME_LIVE, [CAT_DOORBELL, CAT_CAMERA], None],
CAMERA_LAST_MOTION: [
CAMERA_NAME_LAST_MOTION,
[CAT_DOORBELL, CAT_CAMERA],
EVENT_MOTION,
],
CAMERA_LAST_DING: [CAMERA_NAME_LAST_DING, [CAT_DOORBELL], EVENT_DING],
}

# Sensor types: name, category, class
BINARY_SENSORS: Dict[str, list] = {
EVENT_DING: ["Ding", [CAT_DOORBELL], None],
EVENT_MOTION: ["Motion", [CAT_DOORBELL, CAT_CAMERA], DEVICE_CLASS_MOTION],
EVENT_ONLINE: ["Online", [CAT_DOORBELL, CAT_CAMERA], DEVICE_CLASS_CONNECTIVITY],
}

# Sensor types: name, category, class, icon
SENSORS = {
SENSOR_LAST_ACTIVITY: [
"Last Activity",
[CAT_DOORBELL, CAT_CAMERA],
DEVICE_CLASS_TIMESTAMP,
"history",
],
SENSOR_LAST_MOTION: [
"Last Motion",
[CAT_DOORBELL, CAT_CAMERA],
DEVICE_CLASS_TIMESTAMP,
"history",
],
SENSOR_LAST_DING: ["Last Ding", [CAT_DOORBELL], DEVICE_CLASS_TIMESTAMP, "history"],
}
Loading

0 comments on commit 2fbebcb

Please sign in to comment.