Skip to content

Commit

Permalink
Initial release
Browse files Browse the repository at this point in the history
  • Loading branch information
elad-bar committed Apr 14, 2021
0 parents commit 357777c
Show file tree
Hide file tree
Showing 36 changed files with 3,135 additions and 0 deletions.
65 changes: 65 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover

# Translations
*.mo
*.pot

# Django stuff:
*.log

# Sphinx documentation
docs/_build/

# PyBuilder
target/

/.idea
.vscode/

venv/

__test__.py
93 changes: 93 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
repos:
- repo: https://github.com/asottile/pyupgrade
rev: v2.7.2
hooks:
- id: pyupgrade
args: [--py38-plus]
- repo: https://github.com/psf/black
rev: 20.8b1
hooks:
- id: black
args:
- --safe
- --quiet
files: ^((homeassistant|script|tests)/.+)?[^/]+\.py$
- repo: https://github.com/codespell-project/codespell
rev: v2.0.0
hooks:
- id: codespell
args:
- --ignore-words-list=hass,alot,datas,dof,dur,ether,farenheit,hist,iff,ines,ist,lightsensor,mut,nd,pres,referer,ser,serie,te,technik,ue,uint,visability,wan,wanna,withing,iam,incomfort
- --skip="./.*,*.csv,*.json"
- --quiet-level=2
exclude_types: [csv, json]
exclude: ^tests/fixtures/
- repo: https://gitlab.com/pycqa/flake8
rev: 3.8.4
hooks:
- id: flake8
additional_dependencies:
- flake8-docstrings==1.5.0
- pydocstyle==5.1.1
files: ^(homeassistant|script|tests)/.+\.py$
- repo: https://github.com/PyCQA/bandit
rev: 1.7.0
hooks:
- id: bandit
args:
- --quiet
- --format=custom
- --configfile=tests/bandit.yaml
files: ^(homeassistant|script|tests)/.+\.py$
- repo: https://github.com/PyCQA/isort
rev: 5.5.3
hooks:
- id: isort
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0
hooks:
- id: check-executables-have-shebangs
stages: [manual]
- id: check-json
exclude: (.vscode|.devcontainer)
- id: no-commit-to-branch
args:
- --branch=dev
- --branch=master
- --branch=rc
- repo: https://github.com/adrienverge/yamllint.git
rev: v1.24.2
hooks:
- id: yamllint
- repo: https://github.com/prettier/prettier
rev: 2.0.4
hooks:
- id: prettier
stages: [manual]
- repo: local
hooks:
# Run mypy through our wrapper script in order to get the possible
# pyenv and/or virtualenv activated; it may not have been e.g. if
# committing from a GUI tool that was not launched from an activated
# shell.
- id: mypy
name: mypy
entry: script/run-in-env.sh mypy
language: script
types: [python]
require_serial: true
files: ^homeassistant/.+\.py$
- id: gen_requirements_all
name: gen_requirements_all
entry: script/run-in-env.sh python3 -m script.gen_requirements_all
pass_filenames: false
language: script
types: [text]
files: ^(homeassistant/.+/manifest\.json|\.pre-commit-config\.yaml)$
- id: hassfest
name: hassfest
entry: script/run-in-env.sh python3 -m script.hassfest
pass_filenames: false
language: script
types: [text]
files: ^(homeassistant/.+/(manifest|strings)\.json|\.coveragerc)$
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Changelog

## 2021-04-14

Initial release
102 changes: 102 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Shinobi Video NVR

## Description

Integration with Shinobi Video NVR. Creates the following components:

* Camera - per-camera defined.
* Binary Sensors (MOTION, SOUND) - per-camera defined.
* Support HLS Streams instead of H264.
* Support SSL with self-signed certificate.

[Changelog](https://github.com/elad-bar/ha-shinobi/blob/master/CHANGELOG.md)

## How to

#### Requirements
- Shinobi Video Server available with credentials
- MQTT Integration is optional - it will allow to listen to BlueIris event

#### Shinobi links:
- [Using MQTT to receive and trigger events](https://hub.shinobi.video/articles/view/xEMps3O4y4VEaYk)
- [How to use Motion Detection](https://hub.shinobi.video/articles/view/LKdcgcgWy9RJfUh)


#### Installations via HACS
Currently, repository is not under official HACS repo, in order to install, you will need to add manually the repository

Look for "Shinobi Video NVR" and install

#### Integration settings
###### Basic configuration (Configuration -> Integrations -> Add BlueIris)
Fields name | Type | Required | Default | Description
--- | --- | --- | --- | --- |
Host | Texbox | + | None | Hostname or IP address of the BlueIris server
Port | Textbox | + | 0 | HTTP Port to access BlueIris server
SSL | Check-box | + | Unchecked | Is SSL supported?
Username | Textbox | - | | Username of admin user for BlueIris server
Password | Textbox | - | | Password of admin user for BlueIris server

###### Integration options (Configuration -> Integrations -> BlueIris Integration -> Options)
Fields name | Type | Required | Default | Description
--- | --- | --- | --- | --- |
Host | Texbox | + | ast stored hostname | Hostname or IP address of the BlueIris server
Port | Textbox | + | 0ast stored port | HTTP Port to access BlueIris server
SSL | Check-box | + | Last stored SSL flag | Is SSL supported?
Username | Textbox | - | Last stored username | Username of admin user for BlueIris server
Password | Textbox | - | Last stored password | Password of admin user for BlueIris server
Log level | Drop-down | + | Default | Changes component's log level (more details below)

**Log Level's drop-down**
New feature to set the log level for the component without need to set log_level in `customization:` and restart or call manually `logger.set_level` and loose it after restart.

Upon startup or integration's option update, based on the value chosen, the component will make a service call to `logger.set_level` for that component with the desired value,

In case `Default` option is chosen, flow will skip calling the service, after changing from any other option to `Default`, it will not take place automatically, only after restart

###### Configuration validations
Upon submitting the form of creating an integration or updating options,

Component will try to log in into the Shinobi Video server to verify new settings, following errors can appear:
- Integration already configured with the same title
- Invalid server details - Cannot reach the server

###### Encryption key got corrupted
If a persistent notification popped up with the following message:
```
Encryption key got corrupted, please remove the integration and re-add it
```

It means that encryption key was modified from outside the code,
Please remove the integration and re-add it to make it work again.

## Components

#### Binary Sensors
Binary sensor are relying on MQTT, you will need to set up in Shinobi Video Server MQTT plugin and configure each of the monitors to trigger MQTT message.

Each binary sensor will have the name pattern - {Integration Title} {Camera Name} {Sound / Motion},
Once triggered, the following details will be added to the attributes of the binary sensor:

Attributes | Description |
--- | --- |
name | Event name - Yolo / audio
reason | Event details - object / soundChange
tags | relevant for motion only with object detection, will represent the detected object


###### Audio
Represents whether the camera is triggered for noise or not

###### Motion
Represents whether the camera is triggered for motion or not

###### Camera
State: Idle

Attributes | Available values |
--- | --- |
Status | Recording,
Mode | stop (Disabled), start (Watch-Only), record (Record)
Type | H264, MJPEG,
FPS | -
Empty file added custom_components/__init__.py
Empty file.
66 changes: 66 additions & 0 deletions custom_components/shinobi/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
"""
This component provides support for Shinobi Video.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/shinobi/
"""
import logging
import sys

from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant

from .helpers import async_set_ha, clear_ha, get_ha, handle_log_level
from .helpers.const import *

_LOGGER = logging.getLogger(__name__)


async def async_setup(hass, config):
return True


async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up a Shinobi Video component."""
initialized = False

try:
await handle_log_level(hass, entry)

_LOGGER.debug(f"Starting async_setup_entry of {DOMAIN}")
entry.add_update_listener(async_options_updated)

await async_set_ha(hass, entry)

initialized = True

except Exception as ex:
exc_type, exc_obj, tb = sys.exc_info()
line_number = tb.tb_lineno

_LOGGER.error(f"Failed to load Shinobi Video, error: {ex}, line: {line_number}")

return initialized


async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
"""Unload a config entry."""
ha = get_ha(hass, entry.entry_id)

if ha is not None:
await ha.async_remove(entry)

clear_ha(hass, entry.entry_id)

return True


async def async_options_updated(hass: HomeAssistant, entry: ConfigEntry):
"""Triggered by config entry options updates."""
await handle_log_level(hass, entry)

_LOGGER.info(f"async_options_updated, Entry: {entry.as_dict()} ")

ha = get_ha(hass, entry.entry_id)

if ha is not None:
await ha.async_update_entry(entry)
10 changes: 10 additions & 0 deletions custom_components/shinobi/api/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

class APIRequestException(Exception):
endpoint: str
response: dict

def __init__(self, endpoint, response):
super().__init__(f"API Request failed")

self.endpoint = endpoint
self.response = response
Loading

0 comments on commit 357777c

Please sign in to comment.