From 390a6843d2ea71efd576365e02835bdb9ecc705b Mon Sep 17 00:00:00 2001
From: Elad Bar <elad.bar@hotmail.com>
Date: Sun, 31 Dec 2023 08:57:30 +0200
Subject: [PATCH] update integration to HA  v2024.1.0b0

---
 .github/workflows/constraints.txt             |   6 +-
 .github/workflows/hassfest.yaml               |   5 +-
 .github/workflows/pre-commit.yaml             |  41 +----
 .pre-commit-config.yaml                       |  56 ++++---
 .yamllint                                     |  61 ++++++++
 CHANGELOG.md                                  |  27 ++--
 README.md                                     | 141 ++++++++++--------
 bandit.yaml                                   |  20 +++
 blueiris.json                                 |  36 ++---
 .../blueiris/api/blue_iris_api.py             |  10 +-
 custom_components/blueiris/camera.py          |  30 ++--
 .../blueiris/helpers/__init__.py              |  12 +-
 custom_components/blueiris/helpers/const.py   |  12 +-
 .../blueiris/managers/config_flow_manager.py  |  20 ++-
 .../managers/configuration_manager.py         |   4 +-
 .../blueiris/managers/entity_manager.py       |  32 ++--
 custom_components/blueiris/manifest.json      |  30 ++--
 .../blueiris/models/base_entity.py            |   1 -
 .../blueiris/models/camera_data.py            |   3 +-
 custom_components/blueiris/services.yaml      |  14 +-
 custom_components/blueiris/strings.json       |  62 ++++----
 .../blueiris/translations/en.json             |  62 ++++----
 docs/blueiris-server.md                       |  17 ++-
 docs/configs/casting/configuration.yaml       |   2 +-
 docs/configs/casting/ui-lovelace.yaml         |  14 +-
 hacs.json                                     |   2 +-
 info.md                                       | 129 +++++++++-------
 27 files changed, 501 insertions(+), 348 deletions(-)
 create mode 100644 .yamllint
 create mode 100644 bandit.yaml

diff --git a/.github/workflows/constraints.txt b/.github/workflows/constraints.txt
index 75a084f..3bbc4ae 100644
--- a/.github/workflows/constraints.txt
+++ b/.github/workflows/constraints.txt
@@ -1,3 +1,3 @@
-pip==20.3.3
-pre-commit==2.9.3
-nox==2020.12.31
+pip==22.2.2
+pre-commit==2.20.0
+nox==2022.8.7
diff --git a/.github/workflows/hassfest.yaml b/.github/workflows/hassfest.yaml
index 862840e..1ee9922 100644
--- a/.github/workflows/hassfest.yaml
+++ b/.github/workflows/hassfest.yaml
@@ -1,7 +1,6 @@
----
-
 name: Validate with hassfest
 
+# yamllint disable-line rule:truthy
 on:
   push:
   pull_request:
@@ -12,5 +11,5 @@ jobs:
   validate:
     runs-on: "ubuntu-latest"
     steps:
-      - uses: "actions/checkout@v2"
+      - uses: "actions/checkout@v3.1.0"
       - uses: home-assistant/actions/hassfest@master
diff --git a/.github/workflows/pre-commit.yaml b/.github/workflows/pre-commit.yaml
index 9e43ce8..b0e3f19 100644
--- a/.github/workflows/pre-commit.yaml
+++ b/.github/workflows/pre-commit.yaml
@@ -1,42 +1,15 @@
-name: Linting
+name: pre-commit
 
+# yamllint disable-line rule:truthy
 on:
-  push:
-    branches:
-      - main
-      - master
-      - dev
   pull_request:
+  push:
+    branches: [master]
 
 jobs:
   pre-commit:
     runs-on: ubuntu-latest
-    name: pre-commit
     steps:
-      - uses: actions/checkout@v2.3.4
-      - uses: actions/setup-python@v2.2.1
-        with:
-          python-version: "3.9"
-      - run: |
-          pip install --constraint=.github/workflows/constraints.txt pip
-          pip install --constraint=.github/workflows/constraints.txt pre-commit
-      - name: Compute cache key prefix
-        if: matrix.os != 'windows-latest'
-        id: cache_key_prefix
-        shell: python
-        run: |
-          import hashlib
-          import sys
-          python = "py{}.{}".format(*sys.version_info[:2])
-          payload = sys.version.encode() + sys.executable.encode()
-          digest = hashlib.sha256(payload).hexdigest()
-          result = "${{ runner.os }}-{}-{}-pre-commit".format(python, digest)
-          print("::set-output name=result::{}".format(result))
-      - uses: actions/cache@v2.1.3
-        if: matrix.os != 'windows-latest'
-        with:
-          path: ~/.cache/pre-commit
-          key: ${{ steps.cache_key_prefix.outputs.result }}-${{ hashFiles('.pre-commit-config.yaml') }}
-          restore-keys: |
-            ${{ steps.cache_key_prefix.outputs.result }}-
-      - run: pre-commit run --all-files --show-diff-on-failure --color=always
+      - uses: actions/checkout@v3
+      - uses: actions/setup-python@v3
+      - uses: pre-commit/action@v3.0.0
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index e6f41e8..9efca2f 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,21 +1,18 @@
----
-
 repos:
   - repo: https://github.com/asottile/pyupgrade
-    rev: v2.32.1
+    rev: v3.15.0
     hooks:
       - id: pyupgrade
-        args: [ --py39 ]
+        args: [--py39-plus]
   - repo: https://github.com/psf/black
-    rev: 22.3.0
+    rev: 23.12.1
     hooks:
       - id: black
         args:
-          - --safe
           - --quiet
-        files: ^((homeassistant|script|tests)/.+)?[^/]+\.py$
+        files: ^((custom_components)/.+)?[^/]+\.py$
   - repo: https://github.com/codespell-project/codespell
-    rev: v2.1.0
+    rev: v2.2.6
     hooks:
       - id: codespell
         args:
@@ -23,41 +20,54 @@ repos:
           - --skip="./.*,*.csv,*.json"
           - --quiet-level=2
         exclude_types: [csv, json]
-        exclude: ^tests/fixtures/
-  - repo: https://gitlab.com/pycqa/flake8
-    rev: 3.8.4
+  - repo: https://github.com/PyCQA/autoflake
+    rev: v2.2.1
+    hooks:
+      - id: autoflake
+        args:
+          - --in-place
+          - --remove-all-unused-imports
+  - repo: https://github.com/PyCQA/flake8
+    rev: 6.1.0
     hooks:
       - id: flake8
         additional_dependencies:
-          - flake8-docstrings==1.5.0
-          - pydocstyle==5.1.1
-        files: ^(homeassistant|script|tests)/.+\.py$
+          - pycodestyle>=2.10.0
+          - pyflakes>=3.0.1
+          # - flake8-docstrings==1.6.0
+          # - pydocstyle==6.2.3
+          - flake8-comprehensions>=3.10.1
+          - flake8-noqa>=1.3.0
+          - mccabe>=0.7.0
+        files: ^(custom_components)/.+\.py$
   - repo: https://github.com/PyCQA/bandit
-    rev: 1.7.4
+    rev: 1.7.6
     hooks:
       - id: bandit
         args:
           - --quiet
           - --format=custom
-          - --configfile=tests/bandit.yaml
-        files: ^(homeassistant|script|tests)/.+\.py$
+          - --configfile=bandit.yaml
+        files: ^(custom_components)/.+\.py$
   - repo: https://github.com/PyCQA/isort
-    rev: 5.10.1
+    rev: 5.13.2
     hooks:
       - id: isort
   - repo: https://github.com/pre-commit/pre-commit-hooks
-    rev: v3.2.0
+    rev: v4.5.0
     hooks:
-      - id: check-executables-have-shebangs
-        stages: [manual]
       - id: check-json
         exclude: (.vscode|.devcontainer)
       - id: check-yaml
       - id: end-of-file-fixer
       - id: trailing-whitespace
       - id: check-added-large-files
+  - repo: https://github.com/adrienverge/yamllint.git
+    rev: v1.33.0
+    hooks:
+      - id: yamllint
+        exclude: (.yamllint)
   - repo: https://github.com/pre-commit/mirrors-prettier
-    rev: v2.6.1
+    rev: v3.0.3
     hooks:
       - id: prettier
-        stages: [manual]
diff --git a/.yamllint b/.yamllint
new file mode 100644
index 0000000..c2f877a
--- /dev/null
+++ b/.yamllint
@@ -0,0 +1,61 @@
+ignore: |
+  azure-*.yml
+rules:
+  braces:
+    level: error
+    min-spaces-inside: 0
+    max-spaces-inside: 1
+    min-spaces-inside-empty: -1
+    max-spaces-inside-empty: -1
+  brackets:
+    level: error
+    min-spaces-inside: 0
+    max-spaces-inside: 0
+    min-spaces-inside-empty: -1
+    max-spaces-inside-empty: -1
+  colons:
+    level: error
+    max-spaces-before: 0
+    max-spaces-after: 1
+  commas:
+    level: error
+    max-spaces-before: 0
+    min-spaces-after: 1
+    max-spaces-after: 1
+  comments:
+    level: error
+    require-starting-space: true
+    min-spaces-from-content: 2
+  comments-indentation:
+    level: error
+  document-end:
+    level: error
+    present: false
+  document-start:
+    level: error
+    present: false
+  empty-lines:
+    level: error
+    max: 1
+    max-start: 0
+    max-end: 1
+  hyphens:
+    level: error
+    max-spaces-after: 1
+  indentation:
+    level: error
+    spaces: 2
+    indent-sequences: true
+    check-multi-line-strings: false
+  key-duplicates:
+    level: error
+  line-length: disable
+  new-line-at-end-of-file:
+    level: error
+  new-lines:
+    level: error
+    type: unix
+  trailing-spaces:
+    level: error
+  truthy:
+    level: error
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a2ff1c4..4e31b79 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
 # Changelog
 
+## 1.0.16
+
+- Update ConfigEntry to support HA v2024.1.0b0 and above [Issue #218](https://github.com/elad-bar/ha-blueiris/issues/218)
+- Update pre-commit package and configuration files (updated packages)
+- Set minimum version of HA to be supported by HACS as 2024.1.0b0
+- Re-order manifest property order to support hassfest validation
+
 ## 1.0.13
 
 - Device and Entity registry - `async_get_registry` is deprecated, change to `async_get` [\#170](https://github.com/elad-bar/ha-blueiris/issues/170)
@@ -26,7 +33,7 @@
 
 ## 1.0.8
 
-- Fix for 2021.9.0 Breaking Change: Custom integrations: Cameras* [\#127](https://github.com/elad-bar/ha-blueiris/issues/127)
+- Fix for 2021.9.0 Breaking Change: Custom integrations: Cameras\* [\#127](https://github.com/elad-bar/ha-blueiris/issues/127)
 - Fixed Info logging message when setting profile and schedule
 
 ## 1.0.7
@@ -36,17 +43,20 @@
 ## 2021-07-31 (1.0.6)
 
 **Fixed bugs:**
-- Cannot import MQTT Message (HA Core Breaking Change) >=2021.8.* [\#120](https://github.com/elad-bar/ha-blueiris/issues/120)
+
+- Cannot import MQTT Message (HA Core Breaking Change) >=2021.8.\* [\#120](https://github.com/elad-bar/ha-blueiris/issues/120)
 
 ## 2021-07-31 (1.0.6b2)
 
 **Fixed bugs:**
-- Cannot import MQTT Message (HA Core Breaking Change) >=2021.8.* [\#120](https://github.com/elad-bar/ha-blueiris/issues/120)
+
+- Cannot import MQTT Message (HA Core Breaking Change) >=2021.8.\* [\#120](https://github.com/elad-bar/ha-blueiris/issues/120)
 
 ## 2021-07-30 (1.0.6b1)
 
 **Fixed bugs:**
-- Cannot import MQTT Message (HA Core Breaking Change) >=2021.8.* [\#120](https://github.com/elad-bar/ha-blueiris/issues/120)
+
+- Cannot import MQTT Message (HA Core Breaking Change) >=2021.8.\* [\#120](https://github.com/elad-bar/ha-blueiris/issues/120)
 
 ## 2021-02-16
 
@@ -111,6 +121,7 @@
 - Improved generate configuration file process
 
 **Fixed bugs:**
+
 - Fixed - Generate configuration files
 
 ## 2020-07-17
@@ -251,9 +262,9 @@
 **Fixed bugs:**
 
 - Fix issue [\#37](https://github.com/elad-bar/ha-blueiris/issues/37) - Restart of HASS causes all entities to be renamed to defaults <br/>
-  improving the way the component is loading, unloading and discover new entities (sensors, camera and switch).  <br/>
-  the main issue as reported in the past was that once changing the entity_id / name it will return to the original after restart.  <br/>
-  another issue that caused by the way it was handled, upon changing the options (settings) - it took few seconds to present the new entities and sometimes it happened only after restart.  <br/>
+  improving the way the component is loading, unloading and discover new entities (sensors, camera and switch). <br/>
+  the main issue as reported in the past was that once changing the entity_id / name it will return to the original after restart. <br/>
+  another issue that caused by the way it was handled, upon changing the options (settings) - it took few seconds to present the new entities and sometimes it happened only after restart. <br/>
   In that version, the entity_id, name will remain as manually set and changes of options will take place immediately
 
 ## 2020-02-28
@@ -265,14 +276,12 @@
 - Fix issue [\#27](https://github.com/elad-bar/ha-blueiris/issues/27) - when changing switch it doesn't work smoothly and after restart
 - Resources (strings) fixed
 
-
 **Implemented enhancements:**
 
 - Username and password are now optional, if not set, will not create profile's switches
 - Added validation for host, port and SSL state in configuration, if URL is not accessible, will throw an error
 - Validate administrator username and password, in case entered wrong credentials, will throw an error
 
-
 ## 2020-02-07 - v2.0.0 - Breaking change!!!
 
 **Implemented enhancements:**
diff --git a/README.md b/README.md
index 80e064e..0455c78 100644
--- a/README.md
+++ b/README.md
@@ -4,15 +4,16 @@
 
 Integration with Blue Iris Video Security Software. Creates the following components:
 
-* Camera - per-camera defined.
-* MQTT Binary Sensors (MOTION, AUDIO, WATCHDOG) - per-camera defined.
-* Switch (Arm / Unarmed) - only when profiles and admin username and password are provided.
-* Support HLS Streams instead of H264.
-* Support SSL with self-signed certificate.
+- Camera - per-camera defined.
+- MQTT Binary Sensors (MOTION, AUDIO, WATCHDOG) - per-camera defined.
+- Switch (Arm / Unarmed) - only when profiles and admin username and password are provided.
+- Support HLS Streams instead of H264.
+- Support SSL with self-signed certificate.
 
 [Changelog](https://github.com/elad-bar/ha-blueiris/blob/master/CHANGELOG.md)
 
 ## Component is no longer being maintained by elad-bar
+
 I switched to Shinobi Video, if there is an issue, feel free to report, suggest PR and I will approve it
 
 kramttocs is working to maintain it but any assistance or PRs are welcome
@@ -20,43 +21,48 @@ kramttocs is working to maintain it but any assistance or PRs are welcome
 ## How to
 
 #### Requirements
+
 - BlueIris Server available with a user
 - To control profiles, user must have 'admin' level permissions
 - MQTT Integration is optional - it will allow listening to BlueIris events
 - Read the [BlueIris manual](https://github.com/elad-bar/ha-blueiris/blob/master/docs/blueiris-server.md) for this component
 
 #### Installations via HACS
+
 Look for "Blue Iris 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
+
+| 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 | + | Last stored hostname | Hostname or IP address of the BlueIris server
-Port | Textbox | + | Last 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
-Clear credentials | Check-box | + | Unchecked | Workaround to clear the username & password since there is not support for optional fields (Not being stored under options)
-Generate configurations | Check-box | + | Unchecked |  Will take generate store and configuration for HA, more details below (Not being stored under options)
-Log level | Drop-down | + | Default | Changes component's log level (more details below)
-Reset components settings to default | Check-box | + | Unchecked |  Will reset drown-downs of componet's creation to their default (Not being stored under options)
-Camera components | Drop-down | - | All camera | Will create camera for each of the chosen camera
-Motion sensors | Drop-down | - | All non-system camera | Will create binary sensor for each of the chosen camera
-Connectivity sensors | Drop-down | - | All non-system camera | Will create connectivity binary sensor for each of the chosen camera
-Audio sensors | Drop-down | - | All audio supported non-system camera | Will create audio binary sensor for each of the chosen camera
-Profile switches | Drop-down | - | All profiles | Will create switch for each of the chosen profiles
-Stream type | Drop-down | - | H264 | Defines the stream type H264 / MJPG
-Stream support | Check-box | - | False | Defines whether to use `Stream` component for preview camera, requires restart to affect
+
+| Fields name                          | Type      | Required | Default                               | Description                                                                                                                 |
+| ------------------------------------ | --------- | -------- | ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
+| Host                                 | Texbox    | +        | Last stored hostname                  | Hostname or IP address of the BlueIris server                                                                               |
+| Port                                 | Textbox   | +        | Last 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                                                                                  |
+| Clear credentials                    | Check-box | +        | Unchecked                             | Workaround to clear the username & password since there is not support for optional fields (Not being stored under options) |
+| Generate configurations              | Check-box | +        | Unchecked                             | Will take generate store and configuration for HA, more details below (Not being stored under options)                      |
+| Log level                            | Drop-down | +        | Default                               | Changes component's log level (more details below)                                                                          |
+| Reset components settings to default | Check-box | +        | Unchecked                             | Will reset drown-downs of componet's creation to their default (Not being stored under options)                             |
+| Camera components                    | Drop-down | -        | All camera                            | Will create camera for each of the chosen camera                                                                            |
+| Motion sensors                       | Drop-down | -        | All non-system camera                 | Will create binary sensor for each of the chosen camera                                                                     |
+| Connectivity sensors                 | Drop-down | -        | All non-system camera                 | Will create connectivity binary sensor for each of the chosen camera                                                        |
+| Audio sensors                        | Drop-down | -        | All audio supported non-system camera | Will create audio binary sensor for each of the chosen camera                                                               |
+| Profile switches                     | Drop-down | -        | All profiles                          | Will create switch for each of the chosen profiles                                                                          |
+| Stream type                          | Drop-down | -        | H264                                  | Defines the stream type H264 / MJPG                                                                                         |
+| Stream support                       | Check-box | -        | False                                 | Defines whether to use `Stream` component for preview camera, requires restart to affect                                    |
 
 **Integration's title**
 Title will be extracted from BlueIris server's configuration, it will be set upon adding the server, and after every Option's change
@@ -68,7 +74,7 @@ New feature to set the log level for the component without need to set log_level
 
 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 the service call will not happen. Therefore after changing from any other option to `Default` a restart is required.
+In case `Default` option is chosen the service call will not happen. Therefore after changing from any other option to `Default` a restart is required.
 
 **Control component's creation**
 New feature to control which of the components will be created:
@@ -81,24 +87,29 @@ New feature to control which of the components will be created:
 - To restore defaults which allows automatically adding new camera, check the check-box of Reset components settings to default
 
 ###### Auto-generating configurations files:
+
 Will create YAML with all the configurations in the config directory under blueiris.advanced_configurations.yaml:
+
 - Input select (drop-downs)
 - Script to cast based on the selection
 - UI of all the components created by BlueIris based on the description above
 
 [Example of configuration output](https://github.com/elad-bar/ha-blueiris/blob/master/docs/configs/casting/configuration.yaml)
 
-
 ###### Configuration validations
+
 After submitting the form either for a new integration instance or updating options, the component will try to login to the BlueIris server to verify the new settings.
 
 The following errors can appear:
+
 - BlueIris integration ({host}) already configured
 - Invalid administrator credentials - credentials are invalid or user is not an admin
 - 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
 ```
@@ -108,67 +119,77 @@ It means that the encryption key was modified from outside the code and the inte
 ## Components
 
 ###### Binary Sensor - Alerts
+
 Represents whether there is an active alert or not
 
-Attributes |
---- |
-Active alerts # |
-System name |
-Version |
-License |
-Support expiration |
-Logged in User |
-Latitude |
-Longitude |
+| Attributes         |
+| ------------------ |
+| Active alerts #    |
+| System name        |
+| Version            |
+| License            |
+| Support expiration |
+| Logged in User     |
+| Latitude           |
+| Longitude          |
 
 ###### Binary Sensor - Connectivity - Non-system-camera
+
 Represents whether the camera is online or not (based on MQTT message)
 
 ###### Binary Sensor - Audio - Non-system-camera and camera supports audio
+
 Represents whether the camera is triggered for noise or not (based on MQTT message)
 
 ###### Binary Sensor - Motion - Non-system-camera
+
 Represents whether the camera is triggered for motion or not (based on MQTT message)
 
 ###### Binary Sensor - DIO - Non-system-camera
+
 Represents whether the camera is triggered for digital I/O event or not (based on MQTT message)
 
 ###### Binary Sensor - External - Non-system-camera
+
 Represents whether the camera is triggered for external / ONVIF event or not (based on MQTT message)
 
 ###### Camera
-State: Idle
 
-Attributes |
---- |
-FPS |
-Audio support |
-Width |
-Height |
-Is Online |
-Is Recording |
-Issue (Camera is yellow) |
-Alerts # |
-Triggers # |
-Clips # |
-No Signal # |
-Error |
-Group Cameras (list of camera names if a group) |
+State: Idle
 
+| Attributes                                      |
+| ----------------------------------------------- |
+| FPS                                             |
+| Audio support                                   |
+| Width                                           |
+| Height                                          |
+| Is Online                                       |
+| Is Recording                                    |
+| Issue (Camera is yellow)                        |
+| Alerts #                                        |
+| Triggers #                                      |
+| Clips #                                         |
+| No Signal #                                     |
+| Error                                           |
+| Group Cameras (list of camera names if a group) |
 
 ###### Switch - Profile (Per profile)
+
 Allows setting the active profile, only one of the profile switches can be turned on at a time.
 
 If you turn off one of the switches it will behave as follows:
-* Profile #1 is turned off, it will turn on Profile #0
-* Any of the other profiles are turned off, it will turn on Profile #1
+
+- Profile #1 is turned off, it will turn on Profile #0
+- Any of the other profiles are turned off, it will turn on Profile #1
 
 ###### Services
+
 Trigger Camera: Provides the ability to manually trigger a camera or camera group
 
 Move to Preset: Provides the ability to move a camera to a specified preset
 
 ## Lovelace UI Configuration
+
 [Example of UI layout](https://github.com/elad-bar/ha-blueiris/blob/master/docs/configs/casting/configuration.yaml)
 
 ## Casting
diff --git a/bandit.yaml b/bandit.yaml
new file mode 100644
index 0000000..46566cc
--- /dev/null
+++ b/bandit.yaml
@@ -0,0 +1,20 @@
+# https://bandit.readthedocs.io/en/latest/config.html
+
+tests:
+  - B103
+  - B108
+  - B306
+  - B307
+  - B313
+  - B314
+  - B315
+  - B316
+  - B317
+  - B318
+  - B319
+  - B320
+  - B601
+  - B602
+  - B604
+  - B608
+  - B609
diff --git a/blueiris.json b/blueiris.json
index 535fcc5..e79ee7c 100644
--- a/blueiris.json
+++ b/blueiris.json
@@ -1,20 +1,20 @@
 {
-    "blueiris": {
-        "version": "2.0.0",
-        "local_location": "/custom_components/blueiris/__init__.py",
-        "remote_location": "https://raw.githubusercontent.com/elad-bar/ha-blueiris/master/custom_components/blueiris/__init__.py",
-        "visit_repo": "https://github.com/elad-bar/ha-blueiris",
-        "changelog": "https://github.com/elad-bar/ha-blueiris/releases/latest",
-        "resources": [
-            "https://raw.githubusercontent.com/elad-bar/ha-blueiris/master/custom_components/blueiris/binary_sensor.py",
-            "https://raw.githubusercontent.com/elad-bar/ha-blueiris/master/custom_components/blueiris/blue_iris_api.py",
-            "https://raw.githubusercontent.com/elad-bar/ha-blueiris/master/custom_components/blueiris/blue_iris_data.py",
-            "https://raw.githubusercontent.com/elad-bar/ha-blueiris/master/custom_components/blueiris/camera.py",
-            "https://raw.githubusercontent.com/elad-bar/ha-blueiris/master/custom_components/blueiris/const.py",
-            "https://raw.githubusercontent.com/elad-bar/ha-blueiris/master/custom_components/blueiris/home_assistant.py",
-            "https://raw.githubusercontent.com/elad-bar/ha-blueiris/master/custom_components/blueiris/services.yaml",
-            "https://raw.githubusercontent.com/elad-bar/ha-blueiris/master/custom_components/blueiris/switch.py",
-            "https://raw.githubusercontent.com/elad-bar/ha-blueiris/master/custom_components/blueiris/manifest.json"
-        ]
-    }
+  "blueiris": {
+    "version": "2.0.0",
+    "local_location": "/custom_components/blueiris/__init__.py",
+    "remote_location": "https://raw.githubusercontent.com/elad-bar/ha-blueiris/master/custom_components/blueiris/__init__.py",
+    "visit_repo": "https://github.com/elad-bar/ha-blueiris",
+    "changelog": "https://github.com/elad-bar/ha-blueiris/releases/latest",
+    "resources": [
+      "https://raw.githubusercontent.com/elad-bar/ha-blueiris/master/custom_components/blueiris/binary_sensor.py",
+      "https://raw.githubusercontent.com/elad-bar/ha-blueiris/master/custom_components/blueiris/blue_iris_api.py",
+      "https://raw.githubusercontent.com/elad-bar/ha-blueiris/master/custom_components/blueiris/blue_iris_data.py",
+      "https://raw.githubusercontent.com/elad-bar/ha-blueiris/master/custom_components/blueiris/camera.py",
+      "https://raw.githubusercontent.com/elad-bar/ha-blueiris/master/custom_components/blueiris/const.py",
+      "https://raw.githubusercontent.com/elad-bar/ha-blueiris/master/custom_components/blueiris/home_assistant.py",
+      "https://raw.githubusercontent.com/elad-bar/ha-blueiris/master/custom_components/blueiris/services.yaml",
+      "https://raw.githubusercontent.com/elad-bar/ha-blueiris/master/custom_components/blueiris/switch.py",
+      "https://raw.githubusercontent.com/elad-bar/ha-blueiris/master/custom_components/blueiris/manifest.json"
+    ]
+  }
 }
diff --git a/custom_components/blueiris/api/blue_iris_api.py b/custom_components/blueiris/api/blue_iris_api.py
index 003d18d..45482bf 100644
--- a/custom_components/blueiris/api/blue_iris_api.py
+++ b/custom_components/blueiris/api/blue_iris_api.py
@@ -82,7 +82,7 @@ async def async_post(self, data):
 
         try:
             async with self.session.post(
-                    self.url, data=json.dumps(data), ssl=False
+                self.url, data=json.dumps(data), ssl=False
             ) as response:
                 _LOGGER.debug(f"Status of {self.url}: {response.status}")
 
@@ -139,7 +139,9 @@ async def initialize(self):
             )
 
     async def async_update(self):
-        _LOGGER.info(f"Updating data from BI Server ({self.config_manager.config_entry.title})")
+        _LOGGER.info(
+            f"Updating data from BI Server ({self.config_manager.config_entry.title})"
+        )
 
         await self.load_camera()
         await self.load_status()
@@ -296,7 +298,7 @@ async def trigger_camera(self, camera_short_name):
         request_data = {
             "cmd": "trigger",
             "session": self.session_id,
-            "camera": camera_short_name
+            "camera": camera_short_name,
         }
         await self.async_verified_post(request_data)
 
@@ -307,6 +309,6 @@ async def move_to_preset(self, camera_short_name, preset):
             "cmd": "ptz",
             "session": self.session_id,
             "camera": camera_short_name,
-            "button": preset_value
+            "button": preset_value,
         }
         await self.async_verified_post(request_data)
diff --git a/custom_components/blueiris/camera.py b/custom_components/blueiris/camera.py
index 62d1d88..2185c7c 100644
--- a/custom_components/blueiris/camera.py
+++ b/custom_components/blueiris/camera.py
@@ -34,23 +34,22 @@ async def async_setup_entry(hass, config_entry, async_add_devices):
     """Set up the BlueIris Camera."""
     await async_setup_base_entry(
         hass, config_entry, async_add_devices, CURRENT_DOMAIN, get_camera
-        )
+    )
     platform = entity_platform.current_platform.get()
     platform.async_register_entity_service(
-       SERVICE_TRIGGER_CAMERA,
-       {},
-       SERVICE_TRIGGER_CAMERA,
+        SERVICE_TRIGGER_CAMERA,
+        {},
+        SERVICE_TRIGGER_CAMERA,
     )
     platform.async_register_entity_service(
-       SERVICE_MOVE_TO_PRESET,
-       {
-           vol.Required('preset'): cv.positive_int,
-       },
-       SERVICE_MOVE_TO_PRESET,
+        SERVICE_MOVE_TO_PRESET,
+        {
+            vol.Required("preset"): cv.positive_int,
+        },
+        SERVICE_MOVE_TO_PRESET,
     )
 
 
-
 async def async_unload_entry(hass, config_entry):
     _LOGGER.info(f"async_unload_entry {CURRENT_DOMAIN}: {config_entry}")
 
@@ -67,7 +66,7 @@ def get_camera(hass: HomeAssistant, host: str, entity: EntityData):
 
 
 class BlueIrisCamera(Camera, BlueIrisEntity, ABC):
-    """ BlueIris Camera """
+    """BlueIris Camera"""
 
     def __init__(self, hass, device_info):
         super().__init__()
@@ -102,7 +101,6 @@ def __init__(self, hass, device_info):
         self._last_url = None
         self._last_image = None
 
-
     def _immediate_update(self, previous_state: bool):
         if previous_state != self.entity.state:
             _LOGGER.debug(
@@ -125,13 +123,17 @@ def frame_interval(self):
         """Return the interval between frames of the mjpeg stream."""
         return self._frame_interval
 
-    def camera_image(self, width: Optional[int] = None, height: Optional[int] = None) -> Optional[bytes]:
+    def camera_image(
+        self, width: Optional[int] = None, height: Optional[int] = None
+    ) -> Optional[bytes]:
         """Return bytes of camera image."""
         return asyncio.run_coroutine_threadsafe(
             self.async_camera_image(), self.hass.loop
         ).result()
 
-    async def async_camera_image(self, width: Optional[int] = None, height: Optional[int] = None) -> Optional[bytes]:
+    async def async_camera_image(
+        self, width: Optional[int] = None, height: Optional[int] = None
+    ) -> Optional[bytes]:
         """Return a still image response from the camera."""
         try:
             url = self._still_image_url.async_render()
diff --git a/custom_components/blueiris/helpers/__init__.py b/custom_components/blueiris/helpers/__init__.py
index 59c7977..4b73c2b 100644
--- a/custom_components/blueiris/helpers/__init__.py
+++ b/custom_components/blueiris/helpers/__init__.py
@@ -13,13 +13,13 @@
 
 def clear_ha(hass: HomeAssistant, entry_id):
     if DATA_BLUEIRIS not in hass.data:
-        hass.data[DATA_BLUEIRIS] = dict()
+        hass.data[DATA_BLUEIRIS] = {}
 
     del hass.data[DATA_BLUEIRIS][entry_id]
 
 
 def get_ha(hass: HomeAssistant, entry_id):
-    ha_data = hass.data.get(DATA_BLUEIRIS, dict())
+    ha_data = hass.data.get(DATA_BLUEIRIS, {})
     ha = ha_data.get(entry_id)
 
     return ha
@@ -28,7 +28,7 @@ def get_ha(hass: HomeAssistant, entry_id):
 async def async_set_ha(hass: HomeAssistant, entry: ConfigEntry):
     try:
         if DATA_BLUEIRIS not in hass.data:
-            hass.data[DATA_BLUEIRIS] = dict()
+            hass.data[DATA_BLUEIRIS] = {}
 
         if PASSWORD_MANAGER_BLUEIRIS not in hass.data:
             hass.data[PASSWORD_MANAGER_BLUEIRIS] = PasswordManager(hass)
@@ -56,10 +56,12 @@ async def handle_log_level(hass: HomeAssistant, entry: ConfigEntry):
     log_level_data = {f"custom_components.{DOMAIN}": log_level.lower()}
 
     try:
-       await hass.services.async_call(DOMAIN_LOGGER, SERVICE_SET_LEVEL, log_level_data)
+        await hass.services.async_call(DOMAIN_LOGGER, SERVICE_SET_LEVEL, log_level_data)
 
     except Exception as ex:
         exc_type, exc_obj, tb = sys.exc_info()
         line_number = tb.tb_lineno
 
-        _LOGGER.error(f"Failed to set log level. Ensure you have logging enabled in configuration.yaml., error: {ex}, line: {line_number}")
+        _LOGGER.error(
+            f"Failed to set log level. Ensure you have logging enabled in configuration.yaml., error: {ex}, line: {line_number}"
+        )
diff --git a/custom_components/blueiris/helpers/const.py b/custom_components/blueiris/helpers/const.py
index df9e19f..a1c8091 100644
--- a/custom_components/blueiris/helpers/const.py
+++ b/custom_components/blueiris/helpers/const.py
@@ -4,7 +4,6 @@
 https://home-assistant.io/components/switch.blueiris/
 """
 from datetime import timedelta
-from http.client import NOT_ACCEPTABLE
 
 import voluptuous as vol
 
@@ -44,7 +43,14 @@
 BI_ATTR_GROUP = "group"
 BI_ATTR_TYPE = "type"
 
-BI_NON_GENERIC_ATTRIBUTES = [BI_ATTR_NAME, BI_ATTR_ID, BI_ATTR_AUDIO, BI_ATTR_IS_ONLINE, BI_ATTR_GROUP, BI_ATTR_TYPE]
+BI_NON_GENERIC_ATTRIBUTES = [
+    BI_ATTR_NAME,
+    BI_ATTR_ID,
+    BI_ATTR_AUDIO,
+    BI_ATTR_IS_ONLINE,
+    BI_ATTR_GROUP,
+    BI_ATTR_TYPE,
+]
 
 CAMERA_HAS_AUDIO = "has_audio"
 CAMERA_IS_ONLINE = "is_online"
@@ -195,7 +201,7 @@
     BI_CAMERA_TYPE_NETWORK_IP: BI_CAMERA_TYPE_NETWORK_IP_LABEL,
     BI_CAMERA_TYPE_BROADCAST: BI_CAMERA_TYPE_BROADCAST_LABEL,
     BI_CAMERA_TYPE_SCREEN_CAPTURE: BI_CAMERA_TYPE_SCREEN_CAPTURE_LABEL,
-    BI_CAMERA_TYPE_USB_FIREWIRE_ANALOG: BI_CAMERA_TYPE_USB_FIREWIRE_ANALOG_LABEL
+    BI_CAMERA_TYPE_USB_FIREWIRE_ANALOG: BI_CAMERA_TYPE_USB_FIREWIRE_ANALOG_LABEL,
 }
 
 ATTR_BLUE_IRIS_CAMERA = {
diff --git a/custom_components/blueiris/managers/config_flow_manager.py b/custom_components/blueiris/managers/config_flow_manager.py
index 256a163..19e8517 100644
--- a/custom_components/blueiris/managers/config_flow_manager.py
+++ b/custom_components/blueiris/managers/config_flow_manager.py
@@ -237,7 +237,15 @@ def get_default_options(self) -> vol.Schema:
 
     async def _update_entry(self):
         try:
-            entry = ConfigEntry(0, "", "", self._data, "", options=self._options)
+            entry = ConfigEntry(
+                version=0,
+                minor_version=0,
+                domain="",
+                title="",
+                data=self._data,
+                source="",
+                options=self._options,
+            )
 
             await self._config_manager.update(entry)
         except InvalidToken:
@@ -245,7 +253,15 @@ async def _update_entry(self):
 
             del self._data[CONF_PASSWORD]
 
-            entry = ConfigEntry(0, "", "", self._data, "", options=self._options)
+            entry = ConfigEntry(
+                version=0,
+                minor_version=0,
+                domain="",
+                title="",
+                data=self._data,
+                source="",
+                options=self._options,
+            )
 
             await self._config_manager.update(entry)
 
diff --git a/custom_components/blueiris/managers/configuration_manager.py b/custom_components/blueiris/managers/configuration_manager.py
index 2a6090f..f6539f8 100644
--- a/custom_components/blueiris/managers/configuration_manager.py
+++ b/custom_components/blueiris/managers/configuration_manager.py
@@ -44,7 +44,9 @@ async def update(self, config_entry: ConfigEntry):
         )
         result.allowed_profile = self._get_allowed_option(CONF_ALLOWED_PROFILE, options)
 
-        result.allowed_schedule = self._get_allowed_option(CONF_ALLOWED_SCHEDULE, options)
+        result.allowed_schedule = self._get_allowed_option(
+            CONF_ALLOWED_SCHEDULE, options
+        )
 
         result.stream_type = options.get(CONF_STREAM_TYPE, DEFAULT_STREAM_TYPE)
 
diff --git a/custom_components/blueiris/managers/entity_manager.py b/custom_components/blueiris/managers/entity_manager.py
index f7a713c..fb523e0 100644
--- a/custom_components/blueiris/managers/entity_manager.py
+++ b/custom_components/blueiris/managers/entity_manager.py
@@ -1,6 +1,6 @@
 import logging
 import sys
-from typing import Dict, List, Optional
+from typing import Optional
 
 from homeassistant.components.camera import DEFAULT_CONTENT_TYPE
 from homeassistant.components.stream import DOMAIN as DOMAIN_STREAM
@@ -156,12 +156,18 @@ def create_components(self):
         allowed_schedule = config_data.allowed_schedule
         system_device_name = self.system_device_name
 
-        if is_admin and (allowed_profile is None or len(allowed_profile) > 0) and (allowed_schedule is None or len(allowed_schedule) > 0) :
+        if (
+            is_admin
+            and (allowed_profile is None or len(allowed_profile) > 0)
+            and (allowed_schedule is None or len(allowed_schedule) > 0)
+        ):
             for profile_name in available_profiles:
                 profile_id = available_profiles.index(profile_name)
 
                 if allowed_profile is None or str(profile_id) in allowed_profile:
-                    self.generate_profile_switch(profile_id, profile_name, system_device_name)
+                    self.generate_profile_switch(
+                        profile_id, profile_name, system_device_name
+                    )
             for schedule_name in available_schedules:
                 schedule_id = available_schedules.index(schedule_name)
 
@@ -271,7 +277,9 @@ async def _async_update(self):
         except Exception as ex:
             self.log_exception(ex, f"Failed to update, step: {step}")
 
-    def get_profile_switch(self, profile_id, profile_name, system_device_name) -> EntityData:
+    def get_profile_switch(
+        self, profile_id, profile_name, system_device_name
+    ) -> EntityData:
         entity = None
 
         try:
@@ -304,7 +312,9 @@ def get_profile_switch(self, profile_id, profile_name, system_device_name) -> En
 
     def generate_profile_switch(self, profile_id, profile_name, system_device_name):
         try:
-            entity = self.get_profile_switch(profile_id, profile_name, system_device_name)
+            entity = self.get_profile_switch(
+                profile_id, profile_name, system_device_name
+            )
             entity_name = entity.name
 
             self.set_entity(DOMAIN_SWITCH, entity_name, entity)
@@ -338,9 +348,7 @@ def get_schedule_switch(self, schedule_name, system_device_name) -> EntityData:
             entity.icon = SCHEDULE_ICON
             entity.device_name = system_device_name
         except Exception as ex:
-            self.log_exception(
-                ex, f"Failed to get schedule switch {schedule_name}"
-            )
+            self.log_exception(ex, f"Failed to get schedule switch {schedule_name}")
 
         return entity
 
@@ -415,7 +423,9 @@ def generate_main_binary_sensor(self):
         except Exception as ex:
             self.log_exception(ex, "Failed to generate main binary sensor")
 
-    def get_camera_entity(self, camera: CameraData, sensor_type_name, camera_device_name) -> EntityData:
+    def get_camera_entity(
+        self, camera: CameraData, sensor_type_name, camera_device_name
+    ) -> EntityData:
         entity = None
 
         try:
@@ -459,7 +469,9 @@ def generate_camera_binary_sensors(self, camera: CameraData):
             camera_device_name = self.device_manager.get_camera_device_name(camera)
             for sensor_type_name in CAMERA_SENSORS.keys():
                 if self.config_manager.is_allowed_sensor(camera, sensor_type_name):
-                    entity = self.get_camera_entity(camera, sensor_type_name, camera_device_name)
+                    entity = self.get_camera_entity(
+                        camera, sensor_type_name, camera_device_name
+                    )
                     entities.append(entity)
 
             for entity in entities:
diff --git a/custom_components/blueiris/manifest.json b/custom_components/blueiris/manifest.json
index 6307009..f686d5f 100644
--- a/custom_components/blueiris/manifest.json
+++ b/custom_components/blueiris/manifest.json
@@ -1,19 +1,13 @@
 {
-    "domain": "blueiris",
-    "name": "Blue Iris NVR",
-    "documentation": "https://github.com/elad-bar/ha-blueiris",
-    "after_dependencies": [
-        "mqtt"
-    ],
-    "dependencies": [
-        "camera"
-    ],
-    "codeowners": [
-        "@elad-bar",
-        "@kramttocs"
-    ],
-    "requirements": [],
-    "config_flow": true,
-    "version": "1.0.15",
-    "iot_class": "local_polling"
-  }
+  "domain": "blueiris",
+  "name": "Blue Iris NVR",
+  "after_dependencies": ["mqtt"],
+  "codeowners": ["@elad-bar", "@kramttocs"],
+  "config_flow": true,
+  "dependencies": ["camera"],
+  "documentation": "https://github.com/elad-bar/ha-blueiris",
+  "iot_class": "local_polling",
+  "issue_tracker": "https://github.com/elad-bar/ha-blueiris/issues",
+  "requirements": [],
+  "version": "1.0.16"
+}
diff --git a/custom_components/blueiris/models/base_entity.py b/custom_components/blueiris/models/base_entity.py
index 1d9b17e..e8ee7c7 100644
--- a/custom_components/blueiris/models/base_entity.py
+++ b/custom_components/blueiris/models/base_entity.py
@@ -21,7 +21,6 @@ async def async_setup_base_entry(
     domain: str,
     component: Callable[[HomeAssistant, Any, EntityData], Any],
 ):
-
     """Set up BlueIris based off an entry."""
     _LOGGER.debug(f"Starting async_setup_entry {domain}")
 
diff --git a/custom_components/blueiris/models/camera_data.py b/custom_components/blueiris/models/camera_data.py
index ed73f8a..51df58f 100644
--- a/custom_components/blueiris/models/camera_data.py
+++ b/custom_components/blueiris/models/camera_data.py
@@ -18,7 +18,7 @@ def __init__(self, camera):
         self.is_online = camera.get(BI_ATTR_IS_ONLINE, False)
         self.has_audio = camera.get(BI_ATTR_AUDIO, False)
         self.data = camera
-        self.is_group = True if(camera.get(BI_ATTR_GROUP) is not None) else False
+        self.is_group = True if (camera.get(BI_ATTR_GROUP) is not None) else False
         if self.is_group:
             self.group_cameras = camera.get(BI_ATTR_GROUP)
         self.is_system = self.id in SYSTEM_CAMERA_ID
@@ -35,7 +35,6 @@ def __repr__(self):
             CAMERA_DATA: self.data,
             CAMERA_GROUP_CAMERAS: self.group_cameras,
             CAMERA_TYPE: self.type,
-
         }
 
         to_string = f"{obj}"
diff --git a/custom_components/blueiris/services.yaml b/custom_components/blueiris/services.yaml
index 217e437..d103802 100644
--- a/custom_components/blueiris/services.yaml
+++ b/custom_components/blueiris/services.yaml
@@ -2,19 +2,19 @@ trigger_camera:
   name: Trigger Camera
   description: Triggers a camera
   target:
-     entity:
-        integration: blueiris
-        domain: camera
+    entity:
+      integration: blueiris
+      domain: camera
 
 move_to_preset:
   name: Move to Preset
   description: Moves the selected camera to the specified preset
   target:
-     entity:
-        integration: blueiris
-        domain: camera
+    entity:
+      integration: blueiris
+      domain: camera
   fields:
-     preset:
+    preset:
       name: Preset
       description: Desired preset
       required: true
diff --git a/custom_components/blueiris/strings.json b/custom_components/blueiris/strings.json
index 10eea0f..0cd6862 100644
--- a/custom_components/blueiris/strings.json
+++ b/custom_components/blueiris/strings.json
@@ -20,37 +20,37 @@
     }
   },
   "options": {
-      "step": {
-          "blue_iris_additional_settings": {
-              "title": "Options for BlueIris.",
-              "description": "Set up username and password to control profiles / exclude system camera.",
-              "data": {
-                  "host": "Host",
-                  "port": "Port",
-                  "ssl": "Is SSL",
-                  "username": "Username",
-                  "password": "Password",
-                  "clear-credentials": "Clear credentials",
-                  "log_level": "Log level",
-                  "generate-config-files": "Generate configuration files",
-                  "allowed_camera": "Camera components",
-                  "allowed_profile": "Profile switches",
-                  "allowed_schedule": "Schedule switches",
-                  "allowed_motion_sensor": "Motion sensors",
-                  "allowed_audio_sensor": "Audio sensors",
-                  "allowed_connectivity_sensor": "Connectivity sensors",
-                  "allowed_dio_sensor": "DIO sensors",
-                  "allowed_external_sensor": "External sensors",
-                  "reset-components-settings": "Reset components settings to default",
-                  "stream-type": "Stream type",
-                  "support_stream": "Support stream component (Requires restart)"
-              }
-          }
-      },
-      "error": {
-        "invalid_admin_credentials": "Invalid administrator credentials",
-        "invalid_server_details": "Invalid server details",
-        "already_configured": "BlueIris integration already configured with the name"
+    "step": {
+      "blue_iris_additional_settings": {
+        "title": "Options for BlueIris.",
+        "description": "Set up username and password to control profiles / exclude system camera.",
+        "data": {
+          "host": "Host",
+          "port": "Port",
+          "ssl": "Is SSL",
+          "username": "Username",
+          "password": "Password",
+          "clear-credentials": "Clear credentials",
+          "log_level": "Log level",
+          "generate-config-files": "Generate configuration files",
+          "allowed_camera": "Camera components",
+          "allowed_profile": "Profile switches",
+          "allowed_schedule": "Schedule switches",
+          "allowed_motion_sensor": "Motion sensors",
+          "allowed_audio_sensor": "Audio sensors",
+          "allowed_connectivity_sensor": "Connectivity sensors",
+          "allowed_dio_sensor": "DIO sensors",
+          "allowed_external_sensor": "External sensors",
+          "reset-components-settings": "Reset components settings to default",
+          "stream-type": "Stream type",
+          "support_stream": "Support stream component (Requires restart)"
+        }
       }
+    },
+    "error": {
+      "invalid_admin_credentials": "Invalid administrator credentials",
+      "invalid_server_details": "Invalid server details",
+      "already_configured": "BlueIris integration already configured with the name"
+    }
   }
 }
diff --git a/custom_components/blueiris/translations/en.json b/custom_components/blueiris/translations/en.json
index 10eea0f..0cd6862 100644
--- a/custom_components/blueiris/translations/en.json
+++ b/custom_components/blueiris/translations/en.json
@@ -20,37 +20,37 @@
     }
   },
   "options": {
-      "step": {
-          "blue_iris_additional_settings": {
-              "title": "Options for BlueIris.",
-              "description": "Set up username and password to control profiles / exclude system camera.",
-              "data": {
-                  "host": "Host",
-                  "port": "Port",
-                  "ssl": "Is SSL",
-                  "username": "Username",
-                  "password": "Password",
-                  "clear-credentials": "Clear credentials",
-                  "log_level": "Log level",
-                  "generate-config-files": "Generate configuration files",
-                  "allowed_camera": "Camera components",
-                  "allowed_profile": "Profile switches",
-                  "allowed_schedule": "Schedule switches",
-                  "allowed_motion_sensor": "Motion sensors",
-                  "allowed_audio_sensor": "Audio sensors",
-                  "allowed_connectivity_sensor": "Connectivity sensors",
-                  "allowed_dio_sensor": "DIO sensors",
-                  "allowed_external_sensor": "External sensors",
-                  "reset-components-settings": "Reset components settings to default",
-                  "stream-type": "Stream type",
-                  "support_stream": "Support stream component (Requires restart)"
-              }
-          }
-      },
-      "error": {
-        "invalid_admin_credentials": "Invalid administrator credentials",
-        "invalid_server_details": "Invalid server details",
-        "already_configured": "BlueIris integration already configured with the name"
+    "step": {
+      "blue_iris_additional_settings": {
+        "title": "Options for BlueIris.",
+        "description": "Set up username and password to control profiles / exclude system camera.",
+        "data": {
+          "host": "Host",
+          "port": "Port",
+          "ssl": "Is SSL",
+          "username": "Username",
+          "password": "Password",
+          "clear-credentials": "Clear credentials",
+          "log_level": "Log level",
+          "generate-config-files": "Generate configuration files",
+          "allowed_camera": "Camera components",
+          "allowed_profile": "Profile switches",
+          "allowed_schedule": "Schedule switches",
+          "allowed_motion_sensor": "Motion sensors",
+          "allowed_audio_sensor": "Audio sensors",
+          "allowed_connectivity_sensor": "Connectivity sensors",
+          "allowed_dio_sensor": "DIO sensors",
+          "allowed_external_sensor": "External sensors",
+          "reset-components-settings": "Reset components settings to default",
+          "stream-type": "Stream type",
+          "support_stream": "Support stream component (Requires restart)"
+        }
       }
+    },
+    "error": {
+      "invalid_admin_credentials": "Invalid administrator credentials",
+      "invalid_server_details": "Invalid server details",
+      "already_configured": "BlueIris integration already configured with the name"
+    }
   }
 }
diff --git a/docs/blueiris-server.md b/docs/blueiris-server.md
index 484f055..0adb8f5 100644
--- a/docs/blueiris-server.md
+++ b/docs/blueiris-server.md
@@ -1,6 +1,7 @@
 # BlueIris Server Settings
 
 #### User
+
 If you intent to use any of the Blue Iris REST API commands (such as profile switching),
 
 it's recommended you create a separate Administrator user for Home Assistant to connect to, and limit access to LAN only.
@@ -12,7 +13,8 @@ This keeps any accesses or limitations you may wish to set on Home Assistant sep
 ![Blue Iris Edit User](https://github.com/elad-bar/ha-blueiris/blob/master/docs/images/bi-edit_user.png)
 
 #### Web Server
-Enable the Blue Iris Web Server. Select the  `Advanced...` button to proceed to the next step.
+
+Enable the Blue Iris Web Server. Select the `Advanced...` button to proceed to the next step.
 
 ![Blue Iris Web Server](https://github.com/elad-bar/ha-blueiris/blob/master/docs/images/bi-web_server.png)
 
@@ -48,20 +50,22 @@ In the Blue Iris Options panel, on the `Digital IO and IoT` tab under `MQTT`, se
 
 ###### Troubleshooting
 
-* Do you have a MQTT broker set up and configured? It is recommend to use the [Mosquitto MQTT broker](https://www.home-assistant.io/addons/mosquitto/) add-on, instead of the HA embedded broker - Mosquitto appears to be much more robust. Check that the broker is starting up clean and the topics are coming in without pitching errors.
-* Do you have the [MQTT Integration configured](https://www.home-assistant.io/addons/mosquitto/#home-assistant-configuration)? It's not sufficient to just install/start the broker. Make sure to check the `Enable discovery` box when you configure the integration.
+- Do you have a MQTT broker set up and configured? It is recommend to use the [Mosquitto MQTT broker](https://www.home-assistant.io/addons/mosquitto/) add-on, instead of the HA embedded broker - Mosquitto appears to be much more robust. Check that the broker is starting up clean and the topics are coming in without pitching errors.
+- Do you have the [MQTT Integration configured](https://www.home-assistant.io/addons/mosquitto/#home-assistant-configuration)? It's not sufficient to just install/start the broker. Make sure to check the `Enable discovery` box when you configure the integration.
 
   ![Integrations MQTT](https://github.com/elad-bar/ha-blueiris/blob/master/docs/images/ha-integrations_mqtt.png)
 
   ![Integrations MQTT Configure](https://github.com/elad-bar/ha-blueiris/blob/master/docs/images/ha-integrations_mqtt_configure.png)
 
-
 #### Event triggers
+
 For each camera you wish to monitor, select `"Camera properties..."` and on the `Alerts` tab, check `"Post to a web address or MQTT server"` and then select `"Configure..."`.
 
 Binary sensors for motion, external, DIO, audio and watchdog (connectivity) per camera,
 In order to configure it in BlueIris you will need to go to:
+
 ##### Motion / External / DIO
+
 Camera settings -> Alerts:
 Fire when: This camera is triggered
 
@@ -76,6 +80,7 @@ Action section:
 Click on `On alert`,
 
 in the popup window, create new (or modify) alert for MQTT with the following settings:
+
 ```
 Topic - BlueIris/&CAM/Status
 Payload - { "type": "&TYPE", "trigger": "ON" }
@@ -84,7 +89,6 @@ Payload - { "type": "&TYPE", "trigger": "ON" }
 for `On reset` do the same with payload:
 `{ "type": "&TYPE", "trigger": "OFF" }`
 
-
 The alert should be sent for the profile you would like it to trigger.
 
 Note: Triggering the camera manually in BlueIris sends a different &TYPE and will not trigger the motion sensor. Motion must be detected on the camera for the sensor change to be detected.
@@ -95,6 +99,7 @@ Note: Triggering the camera manually in BlueIris sends a different &TYPE and wil
 ![Blue Iris MQTT Alert](https://github.com/elad-bar/ha-blueiris/blob/master/docs/images/bi-alerts-settings.png)
 
 ##### Audio
+
 Camera settings -> Audio -> Options:<br/>
 Check the `Trigger the camera during profiles` and mark all profiles you would like it to trigger<br/>
 Check the `Use 1 second average intensity` and set the sensitivity level to the desired level<br/>
@@ -104,9 +109,11 @@ Payloads will be sent according to the definition in the Alert's section defined
 ![Blue Iris Alerts](https://github.com/elad-bar/ha-blueiris/blob/master/docs/images/bi-audio-alerts.png)
 
 ##### Watchdog (Connectivity)
+
 Camera settings -> Watchdog<br/>
 in the action's section click on `On loss of signal`, <br/>
 then in the popup window, create new (or modify) alert for MQTT with the following settings:
+
 ```
 Topic - BlueIris/&CAM/Status
 Payload - { "type": "Connectivity", "trigger": "OFF" }
diff --git a/docs/configs/casting/configuration.yaml b/docs/configs/casting/configuration.yaml
index b1fd73f..fd8c118 100644
--- a/docs/configs/casting/configuration.yaml
+++ b/docs/configs/casting/configuration.yaml
@@ -46,4 +46,4 @@ script:
             {% elif is_state('input_select.camera_dropdown', 'All Cameras') %}
               http://192.168.0.10:8081/mjpg/index?/video.mjpg
             {% endif %}
-          media_content_type: 'image/jpg'
+          media_content_type: "image/jpg"
diff --git a/docs/configs/casting/ui-lovelace.yaml b/docs/configs/casting/ui-lovelace.yaml
index 3e90bd2..199c5a8 100644
--- a/docs/configs/casting/ui-lovelace.yaml
+++ b/docs/configs/casting/ui-lovelace.yaml
@@ -1,8 +1,8 @@
 # Example ui-lovelace.yaml view entry
-  - type: entities
-    title: Cast Camera to Screen
-    show_header_toggle: false
-    entities:
-      - entity: input_select.camera_dropdown
-      - entity: input_select.cast_to_screen_dropdown
-      - entity: script.execute_cast_dropdown
+- type: entities
+  title: Cast Camera to Screen
+  show_header_toggle: false
+  entities:
+    - entity: input_select.camera_dropdown
+    - entity: input_select.cast_to_screen_dropdown
+    - entity: script.execute_cast_dropdown
diff --git a/hacs.json b/hacs.json
index 23316fc..bf0486c 100644
--- a/hacs.json
+++ b/hacs.json
@@ -1,5 +1,5 @@
 {
   "name": "BlueIris NVR",
   "iot_class": "Local Polling",
-  "homeassistant": "2021.12.0"
+  "homeassistant": "2024.1.0b0"
 }
diff --git a/info.md b/info.md
index b9d47f1..a681b7f 100644
--- a/info.md
+++ b/info.md
@@ -4,54 +4,59 @@
 
 Integration with Blue Iris Video Security Software. Creates the following components:
 
-* Camera - per-camera defined.
-* MQTT Binary Sensors (MOTION, AUDIO, WATCHDOG) - per-camera defined.
-* Switch (Arm / Unarmed) - only when profiles and admin username and password are provided.
-* Support HLS Streams instead of H264.
-* Support SSL with self-signed certificate.
+- Camera - per-camera defined.
+- MQTT Binary Sensors (MOTION, AUDIO, WATCHDOG) - per-camera defined.
+- Switch (Arm / Unarmed) - only when profiles and admin username and password are provided.
+- Support HLS Streams instead of H264.
+- Support SSL with self-signed certificate.
 
 [Changelog](https://github.com/elad-bar/ha-blueiris/blob/master/CHANGELOG.md)
 
 ## How to
 
 #### Requirements
+
 - BlueIris Server available with a user
 - To control profiles, user must have 'admin' level permissions
 - MQTT Integration is optional - it will allow to listen to BlueIris event
 - Read the [BlueIris manual](https://github.com/elad-bar/ha-blueiris/blob/master/docs/blueiris-server.md) for this component
 
 #### Installations via HACS
+
 Look for "Blue Iris 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
+
+| 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
-Clear credentials | Check-box | + | Unchecked | Workaround to clear the username & password since there is not support for optional fields (Not being stored under options)
-Generate configurations | Check-box | + | Unchecked |  Will take generate store and configuration for HA, more details below (Not being stored under options)
-Log level | Drop-down | + | Default | Changes component's log level (more details below)
-Reset components settings to default | Check-box | + | Unchecked |  Will reset drown-downs of componet's creation to their default (Not being stored under options)
-Camera components | Drop-down | - | All camera | Will create camera for each of the chosen camera
-Motion sensors | Drop-down | - | All non-system camera | Will create binary sensor for each of the chosen camera
-Connectivity sensors | Drop-down | - | All non-system camera | Will create connectivity binary sensor for each of the chosen camera
-Audio sensors | Drop-down | - | All audio supported non-system camera | Will create audio binary sensor for each of the chosen camera
-Profile switches | Drop-down | - | All profiles | Will create switch for each of the chosen profiles
-Stream type | Drop-down | - | H264 | Defines the stream type H264 / MJPG
-Stream support | Check-box | - | False | Defines whether to use `Stream` component for preview camera, requires restart to affect
+
+| 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                                                                                  |
+| Clear credentials                    | Check-box | +        | Unchecked                             | Workaround to clear the username & password since there is not support for optional fields (Not being stored under options) |
+| Generate configurations              | Check-box | +        | Unchecked                             | Will take generate store and configuration for HA, more details below (Not being stored under options)                      |
+| Log level                            | Drop-down | +        | Default                               | Changes component's log level (more details below)                                                                          |
+| Reset components settings to default | Check-box | +        | Unchecked                             | Will reset drown-downs of componet's creation to their default (Not being stored under options)                             |
+| Camera components                    | Drop-down | -        | All camera                            | Will create camera for each of the chosen camera                                                                            |
+| Motion sensors                       | Drop-down | -        | All non-system camera                 | Will create binary sensor for each of the chosen camera                                                                     |
+| Connectivity sensors                 | Drop-down | -        | All non-system camera                 | Will create connectivity binary sensor for each of the chosen camera                                                        |
+| Audio sensors                        | Drop-down | -        | All audio supported non-system camera | Will create audio binary sensor for each of the chosen camera                                                               |
+| Profile switches                     | Drop-down | -        | All profiles                          | Will create switch for each of the chosen profiles                                                                          |
+| Stream type                          | Drop-down | -        | H264                                  | Defines the stream type H264 / MJPG                                                                                         |
+| Stream support                       | Check-box | -        | False                                 | Defines whether to use `Stream` component for preview camera, requires restart to affect                                    |
 
 **Integration's title**
 Title will be extracted from BlueIris server's configuration, it will be set upon adding the server, and after every Option's change
@@ -76,24 +81,29 @@ New feature to control which of the components will be created:
 - To restore defaults which allows automatically adding new camera, check the check-box of Reset components settings to default
 
 ###### Auto-generating configurations files:
+
 Will create YAML with all the configurations in the config directory under blueiris.advanced_configurations.yaml:
+
 - Input select (drop-downs)
 - Script to cast based on the selection
 - UI of all the components created by BlueIris based on the description above
 
 [Example of configuration output](https://github.com/elad-bar/ha-blueiris/blob/master/docs/configs/casting/configuration.yaml)
 
-
 ###### Configuration validations
+
 Upon submitting the form of creating an integration or updating options,
 
 Component will try to login to the BlueIris server to verify new settings, following errors can appear:
+
 - BlueIris integration ({host}) already configured
 - Invalid administrator credentials - credentials are invalid or user is not an admin
 - 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
 ```
@@ -104,53 +114,61 @@ Please remove the integration and re-add it to make it work again.
 ## Components
 
 ###### Binary Sensor - Alerts
+
 Represents whether there is an active alert or not
 
-Attributes |
---- |
-Active alerts # |
-System name |
-Version |
-License |
-Support expiration |
-Logged in User |
-Latitude |
-Longitude |
+| Attributes         |
+| ------------------ |
+| Active alerts #    |
+| System name        |
+| Version            |
+| License            |
+| Support expiration |
+| Logged in User     |
+| Latitude           |
+| Longitude          |
 
 ###### Binary Sensor - Connectivity - Non-system-camera
+
 Represents whether the camera is online or not (based on MQTT message)
 
 ###### Binary Sensor - Audio - Non-system-camera and camera supports audio
+
 Represents whether the camera is triggered for noise or not (based on MQTT message)
 
 ###### Binary Sensor - Motion - Non-system-camera
+
 Represents whether the camera is triggered for motion or not (based on MQTT message)
 
 ###### Binary Sensor - DIO - Non-system-camera
+
 Represents whether the camera is triggered for digital I/O event or not (based on MQTT message)
 
 ###### Binary Sensor - External - Non-system-camera
+
 Represents whether the camera is triggered for external / ONVIF event or not (based on MQTT message)
 
 ###### Camera
+
 State: Idle
 
-Attributes |
---- |
-FPS |
-Audio support |
-Width |
-Height |
-Is Online |
-Is Recording |
-Issue (Camera is yellow) |
-Alerts # |
-Triggers # |
-Clips # |
-No Signal # |
-Error |
+| Attributes               |
+| ------------------------ |
+| FPS                      |
+| Audio support            |
+| Width                    |
+| Height                   |
+| Is Online                |
+| Is Recording             |
+| Issue (Camera is yellow) |
+| Alerts #                 |
+| Triggers #               |
+| Clips #                  |
+| No Signal #              |
+| Error                    |
 
 ###### Switch - Profile (Per profile)
+
 Allows to set the active profile, only one of the profile switches can be turned on at a time
 
 If you are turning off one of the switch it will work according to the following order:
@@ -158,6 +176,7 @@ Profile #1 turned off, will turn on Profile #0
 All the other profiles upon turning off, will turn on Profile #1
 
 ## Lovelace UI Configuration
+
 [Example of UI layout](https://github.com/elad-bar/ha-blueiris/blob/master/docs/configs/casting/configuration.yaml)
 
 ## Casting