Skip to content

Commit

Permalink
Update
Browse files Browse the repository at this point in the history
  • Loading branch information
aneisch committed Aug 25, 2023
1 parent a372a47 commit d772b7d
Show file tree
Hide file tree
Showing 27 changed files with 331 additions and 220 deletions.
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
[![Build Status](https://github.com/aneisch/home-assistant-config/actions/workflows/check-ha-release-compatibility.yml/badge.svg)](https://github.com/aneisch/home-assistant-config/actions)
[![GitHub last commit](https://img.shields.io/github/last-commit/aneisch/home-assistant-config)](https://github.com/aneisch/home-assistant-config/commits/master)
[![GitHub commit activity](https://img.shields.io/github/commit-activity/y/aneisch/home-assistant-config)](https://github.com/aneisch/home-assistant-config/graphs/commit-activity)
[![HA Version](https://img.shields.io/badge/Running%20Home%20Assistant-2023.8.2%20(Latest)-brightgreen)](https://github.com/home-assistant/home-assistant/releases/latest)
[![HA Version](https://img.shields.io/badge/Running%20Home%20Assistant-2023.8.4%20(Latest)-brightgreen)](https://github.com/home-assistant/home-assistant/releases/latest)
<br><a href="https://www.buymeacoffee.com/aneisch" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-black.png" width="150px" height="35px" alt="Buy Me A Coffee" style="height: 35px !important;width: 150px !important;" ></a>


Expand Down Expand Up @@ -56,7 +56,7 @@ Also using Grafana/Influx for graphing, both running in Docker containers on NUC
Description | value
-- | --
Lines of ESPHome YAML | 2353
Lines of Home Assistant YAML | 7759
Lines of Home Assistant YAML | 7787
[Integrations](https://www.home-assistant.io/integrations/) in use | 50
Zigbee devices in [`zha`](https://www.home-assistant.io/integrations/zha/) | 26
Z-Wave devices in [`zwave_js`](https://www.home-assistant.io/integrations/zwave_js/) | 37
Expand All @@ -65,10 +65,10 @@ Description | value
-- | --
Entities in the [`alarm_control_panel`](https://www.home-assistant.io/components/alarm_control_panel) domain | 1
Entities in the [`automation`](https://www.home-assistant.io/components/automation) domain | 98
Entities in the [`binary_sensor`](https://www.home-assistant.io/components/binary_sensor) domain | 116
Entities in the [`button`](https://www.home-assistant.io/components/button) domain | 11
Entities in the [`binary_sensor`](https://www.home-assistant.io/components/binary_sensor) domain | 117
Entities in the [`button`](https://www.home-assistant.io/components/button) domain | 12
Entities in the [`calendar`](https://www.home-assistant.io/components/calendar) domain | 1
Entities in the [`camera`](https://www.home-assistant.io/components/camera) domain | 16
Entities in the [`camera`](https://www.home-assistant.io/components/camera) domain | 17
Entities in the [`climate`](https://www.home-assistant.io/components/climate) domain | 1
Entities in the [`counter`](https://www.home-assistant.io/components/counter) domain | 1
Entities in the [`cover`](https://www.home-assistant.io/components/cover) domain | 8
Expand All @@ -81,7 +81,7 @@ Entities in the [`input_number`](https://www.home-assistant.io/components/input_
Entities in the [`input_select`](https://www.home-assistant.io/components/input_select) domain | 19
Entities in the [`input_text`](https://www.home-assistant.io/components/input_text) domain | 5
Entities in the [`light`](https://www.home-assistant.io/components/light) domain | 37
Entities in the [`lock`](https://www.home-assistant.io/components/lock) domain | 2
Entities in the [`lock`](https://www.home-assistant.io/components/lock) domain | 3
Entities in the [`media_player`](https://www.home-assistant.io/components/media_player) domain | 12
Entities in the [`number`](https://www.home-assistant.io/components/number) domain | 5
Entities in the [`person`](https://www.home-assistant.io/components/person) domain | 2
Expand All @@ -90,17 +90,17 @@ Entities in the [`remote`](https://www.home-assistant.io/components/remote) doma
Entities in the [`scene`](https://www.home-assistant.io/components/scene) domain | 2
Entities in the [`script`](https://www.home-assistant.io/components/script) domain | 39
Entities in the [`select`](https://www.home-assistant.io/components/select) domain | 2
Entities in the [`sensor`](https://www.home-assistant.io/components/sensor) domain | 360
Entities in the [`sensor`](https://www.home-assistant.io/components/sensor) domain | 362
Entities in the [`siren`](https://www.home-assistant.io/components/siren) domain | 1
Entities in the [`sun`](https://www.home-assistant.io/components/sun) domain | 1
Entities in the [`switch`](https://www.home-assistant.io/components/switch) domain | 149
Entities in the [`switch`](https://www.home-assistant.io/components/switch) domain | 147
Entities in the [`timer`](https://www.home-assistant.io/components/timer) domain | 2
Entities in the [`tts`](https://www.home-assistant.io/components/tts) domain | 1
Entities in the [`update`](https://www.home-assistant.io/components/update) domain | 2
Entities in the [`vacuum`](https://www.home-assistant.io/components/vacuum) domain | 1
Entities in the [`weather`](https://www.home-assistant.io/components/weather) domain | 2
Entities in the [`zone`](https://www.home-assistant.io/components/zone) domain | 6
**Total state objects** | **990**
**Total state objects** | **994**
## The HACS integrations/plugins that I use:
**Appdaemon**:<br>
[aneisch/follow_me_appdaemon](https://github.com/aneisch/follow_me_appdaemon)<br>
Expand Down
5 changes: 3 additions & 2 deletions automations.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,8 @@
- sensor.2_battery_level
- sensor.3_battery_level
- sensor.back_bedroom_remote_battery_level
- sensor.front_door_battery_level
- sensor.front_door_battery
- sensor.back_door_battery
- sensor.garage_exterior_door_battery_level
- sensor.back_bathroom_toilet_water_detector_battery_level
- sensor.guest_bathroom_toilet_water_detector_battery_level
Expand Down Expand Up @@ -677,7 +678,7 @@
condition: "{{ states('sensor.fingerprint_last_finger_id') in ['1','2'] }}"
action:
- service: lock.unlock
entity_id: lock.front_door
entity_id: lock.back_door
- service: script.notify_wrapper
data:
message: "Front door unlocked by {% if states('sensor.fingerprint_last_finger_id') == '1' %}Andrew right index{% elif states('sensor.fingerprint_last_finger_id') == '2' %}Andrew left index{% else %}Unknown{% endif %}!"
Expand Down
7 changes: 6 additions & 1 deletion configuration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,11 @@ timer:

tts:
- platform: picotts
- platform: microsoft
api_key: !secret AzureSpeechKey
region: centralus
gender: Male
type: GuyNeural

wemo:
discovery: false
Expand All @@ -537,7 +542,7 @@ utility_meter:
cron: "0 22 L * *"

zha:
enable_quirks: true
#enable_quirks: true
#custom_quirks_path: /config/custom_zha_quirks/
zigpy_config:
network:
Expand Down
50 changes: 19 additions & 31 deletions custom_components/webrtc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import time
import uuid
from pathlib import Path
from typing import Union
from urllib.parse import urlencode, urljoin

import homeassistant.helpers.config_validation as cv
Expand Down Expand Up @@ -43,6 +44,7 @@
vol.Required(ATTR_ENTITY_ID): cv.entity_ids,
vol.Exclusive("url", "url"): cv.string,
vol.Exclusive("entity", "url"): cv.entity_id,
vol.Optional("force", default=False): bool,
vol.Optional("extra"): dict,
},
required=True,
Expand Down Expand Up @@ -105,6 +107,7 @@ async def dash_cast(call: ServiceCallType):
hass,
call.data[ATTR_ENTITY_ID],
f"{get_url(hass)}/webrtc/embed?" + urlencode(query),
call.data.get("force"),
)

hass.services.async_register(DOMAIN, "create_link", create_link, CREATE_LINK_SCHEMA)
Expand Down Expand Up @@ -146,44 +149,29 @@ async def async_unload_entry(hass: HomeAssistantType, entry: ConfigEntry):
return True


async def ws_connect(hass: HomeAssistantType, params) -> str:
entry = hass.data[DOMAIN]
if isinstance(entry, Server):
assert entry.available, "WebRTC server not available"
go_url = "http://localhost:1984/"
else:
go_url = entry

if entity := params.get("entity"):
src = await utils.get_stream_source(hass, entity)
assert src, f"Can't get URL for {entity}"

# adds stream to go2rtc using entity_id as name (RTSPtoWebRTC API)
session = async_get_clientsession(hass)
r = await session.patch(
urljoin(go_url, "api/streams"),
params={"name": entity, "src": src},
timeout=3,
)
assert r.ok, f"Can't update URL for {entity}"
src = entity
async def ws_connect(hass: HomeAssistantType, params: dict) -> str:
# 1. Server URL from card param
server: str = params.get("server")
# 2. Server URL from integration settings
if not server:
server: Union[str, Server] = hass.data[DOMAIN]
# 3. Server is manual binary
if isinstance(server, Server):
assert server.available, "WebRTC server not available"
server = "http://localhost:1984/"

if name := params.get("entity"):
src = await utils.get_stream_source(hass, name)
assert src, f"Can't get URL for {name}"
query = {"src": src, "name": name}
elif src := params.get("url"):
if "{{" in src or "{%" in src:
src = Template(src, hass).async_render()

session = async_get_clientsession(hass)
r = await session.patch(
urljoin(go_url, "api/streams"),
params={"name": src, "src": src},
timeout=3,
)
assert r.ok, f"Can't update URL for {src}"

query = {"src": src}
else:
raise Exception("Missing url or entity")

return urljoin("ws" + go_url[4:], "api/ws") + "?" + urlencode({"src": src})
return urljoin("ws" + server[4:], "api/ws") + "?" + urlencode(query)


class WebSocketView(HomeAssistantView):
Expand Down
2 changes: 1 addition & 1 deletion custom_components/webrtc/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@
"lovelace"
],
"requirements": [],
"version": "v3.2.1",
"version": "v3.3.0",
"iot_class": "calculated"
}
5 changes: 5 additions & 0 deletions custom_components/webrtc/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ dash_cast:
selector:
text:

force:
description: Force restart DashCast application
selector:
boolean:

entity:
description: Camera entity
example: camera.generic_stream
Expand Down
6 changes: 3 additions & 3 deletions custom_components/webrtc/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

DOMAIN = "webrtc"

BINARY_VERSION = "1.6.0"
BINARY_VERSION = "1.6.2"

SYSTEM = {
"Windows": {"AMD64": "go2rtc_win64.zip", "ARM64": "go2rtc_win_arm64.zip"},
Expand Down Expand Up @@ -169,7 +169,7 @@ async def init_resource(hass: HomeAssistant, url: str, ver: str) -> bool:


# noinspection PyProtectedMember
def dash_cast(hass: HomeAssistant, cast_entities: list, url: str):
def dash_cast(hass: HomeAssistant, cast_entities: list, url: str, force=False):
"""Cast webpage to chromecast device via DashCast application."""
try:
entities = [
Expand All @@ -188,7 +188,7 @@ def dash_cast(hass: HomeAssistant, cast_entities: list, url: str):
entity._chromecast.register_handler(entity.dashcast)

_LOGGER.debug(f"DashCast to {entity.entity_id}")
entity.dashcast.load_url(url)
entity.dashcast.load_url(url, force)

except Exception:
_LOGGER.exception(f"Can't DashCast to {cast_entities}")
Expand Down
40 changes: 31 additions & 9 deletions custom_components/webrtc/www/digital-ptz.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const DEFAULT_OPTIONS = {
persist: true,
};
export class DigitalPTZ {
constructor(containerEl, videoEl, options) {
constructor(containerEl, transformEl, videoEl, options) {
this.offHandles = [];
this.recomputeRects = () => {
this.transform.updateRects(this.videoEl, this.containerEl);
Expand All @@ -23,14 +23,15 @@ export class DigitalPTZ {
this.render = (transition = false) => {
if (transition) {
// transition is used to animate dbl click zoom
this.videoEl.style.transition = "transform 200ms";
this.transformEl.style.transition = "transform 200ms";
setTimeout(() => {
this.videoEl.style.transition = "";
this.transformEl.style.transition = "";
}, 200);
}
this.videoEl.style.transform = this.transform.render();
this.transformEl.style.transform = this.transform.render();
};
this.containerEl = containerEl;
this.transformEl = transformEl;
this.videoEl = videoEl;
this.options = Object.assign({}, DEFAULT_OPTIONS, options);
this.transform = new Transform({
Expand Down Expand Up @@ -179,11 +180,12 @@ function startGesturePan({ containerEl, transform, render }, type) {
type === "mouse"
? ["mousedown", "mousemove", "mouseup"]
: ["touchstart", "touchmove", "touchend"];
const isTouchEvent = ev => 'TouchEvent' in window && ev instanceof TouchEvent;
const onDown = (downEvt) => {
let last = downEvt instanceof TouchEvent ? downEvt.touches[0] : downEvt;
let last = isTouchEvent(downEvt) ? downEvt.touches[0] : downEvt;
const onMove = (moveEvt) => {
if (moveEvt instanceof TouchEvent && moveEvt.touches.length !== 1) return;
const curr = moveEvt instanceof TouchEvent ? moveEvt.touches[0] : moveEvt;
if (isTouchEvent(moveEvt) && moveEvt.touches.length !== 1) return;
const curr = isTouchEvent(moveEvt) ? moveEvt.touches[0] : moveEvt;
transform.move(curr.pageX - last.pageX, curr.pageY - last.pageY);
last = curr;
render();
Expand All @@ -205,6 +207,25 @@ function startMouseDragPan(params) {
/** Transform */
const PERSIST_KEY_PREFIX = "webrtc-digital-ptc:";
const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
function getTransformedDimensions(video) {
const { videoWidth, videoHeight } = video;
if (!videoHeight || !videoWidth) return undefined;
var transform = window.getComputedStyle(video).getPropertyValue("transform");
const match = transform.match(/matrix\((.+)\)/);
if (!match || !match[1]) return { videoWidth, videoHeight }; // the video isn't transformed
const matrix = new DOMMatrix(match[1].split(", ").map(Number));
const points = [
new DOMPoint(0, 0),
new DOMPoint(videoWidth, 0),
new DOMPoint(0, videoHeight),
new DOMPoint(videoWidth, videoHeight),
].map((point) => point.matrixTransform(matrix));
const minX = Math.min(...points.map((point) => point.x));
const maxX = Math.max(...points.map((point) => point.x));
const minY = Math.min(...points.map((point) => point.y));
const maxY = Math.max(...points.map((point) => point.y));
return { videoWidth: maxX - minX, videoHeight: maxY - minY };
}
class Transform {
constructor(settings) {
this.scale = 1;
Expand Down Expand Up @@ -252,7 +273,8 @@ class Transform {
return;
}
this.containerRect = containerRect;
if (!videoEl.videoWidth) {
const transformed = getTransformedDimensions(videoEl);
if (!transformed) {
// The video hasn't loaded yet.
// Once it loads, the videometadata listener will call this function again.
return;
Expand All @@ -262,7 +284,7 @@ class Transform {
// This needs to be accounted for when panning, the code below keeps track of that.
const screenAspectRatio =
this.containerRect.width / this.containerRect.height;
const videoAspectRatio = videoEl.videoWidth / videoEl.videoHeight;
const videoAspectRatio = transformed.videoWidth / transformed.videoHeight;
if (videoAspectRatio > screenAspectRatio) {
// Black bars on the top and bottom
const videoHeight = this.containerRect.width / videoAspectRatio;
Expand Down
Binary file modified custom_components/webrtc/www/digital-ptz.js.gz
Binary file not shown.
21 changes: 16 additions & 5 deletions custom_components/webrtc/www/video-rtc.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ export class VideoRTC extends HTMLElement {
'hvc1.1.6.L153.B0', // H.265 main 5.1 (Chromecast Ultra)
'mp4a.40.2', // AAC LC
'mp4a.40.5', // AAC HE
'null', // for detecting liars (Safari iOS 12)
'flac', // FLAC (PCM compatible)
'opus', // OPUS Chrome, Firefox
];
Expand Down Expand Up @@ -241,6 +240,14 @@ export class VideoRTC extends HTMLElement {

this.appendChild(this.video);

// all Safari lies about supported audio codecs
const m = window.navigator.userAgent.match(/Version\/(\d+).+Safari/);
if (m) {
// AAC from v13, FLAC from v14, OPUS - unsupported
const skip = m[1] < '13' ? 'mp4a.40.2' : m[1] < '14' ? 'flac' : 'opus';
this.CODECS.splice(this.CODECS.indexOf(skip));
}

if (this.background) return;

if ('hidden' in document && this.visibilityCheck) {
Expand Down Expand Up @@ -544,12 +551,16 @@ export class VideoRTC extends HTMLElement {
this.pcState = WebSocket.OPEN;

this.wsState = WebSocket.CLOSED;
this.ws.close();
this.ws = null;
if (this.ws) {
this.ws.close();
this.ws = null;
}
} else {
this.pcState = WebSocket.CLOSED;
this.pc.close();
this.pc = null;
if (this.pc) {
this.pc.close();
this.pc = null;
}
}
}

Expand Down
Binary file modified custom_components/webrtc/www/video-rtc.js.gz
Binary file not shown.
Loading

0 comments on commit d772b7d

Please sign in to comment.