Browser state sensors and Visit device for FKB
This commit is contained in:
parent
1109980d61
commit
a46d2b3cb0
@ -937,6 +937,8 @@ const MediaPlayerMixin = (SuperClass) => {
|
||||
|
||||
const CameraMixin = (SuperClass) => {
|
||||
return class CameraMixinClass extends SuperClass {
|
||||
// TODO: Enable WebRTC?
|
||||
// https://levelup.gitconnected.com/establishing-the-webrtc-connection-videochat-with-javascript-step-3-48d4ae0e9ea4
|
||||
constructor() {
|
||||
super();
|
||||
this._framerate = 2;
|
||||
@ -1041,6 +1043,46 @@ const RequireInteractMixin = (SuperClass) => {
|
||||
};
|
||||
};
|
||||
|
||||
const BrowserStateMixin = (SuperClass) => {
|
||||
return class BrowserStateMixinClass extends SuperClass {
|
||||
constructor() {
|
||||
super();
|
||||
document.addEventListener("visibilitychange", () => this._browser_state_update());
|
||||
window.addEventListener("location-changed", () => this._browser_state_update());
|
||||
this.connectionPromise.then(() => this._browser_state_update());
|
||||
}
|
||||
_browser_state_update() {
|
||||
const update = async () => {
|
||||
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
||||
const battery = (_b = (_a = navigator).getBattery) === null || _b === void 0 ? void 0 : _b.call(_a);
|
||||
this.sendUpdate({
|
||||
browser: {
|
||||
path: window.location.pathname,
|
||||
visibility: document.visibilityState,
|
||||
userAgent: navigator.userAgent,
|
||||
currentUser: (_d = (_c = this.hass) === null || _c === void 0 ? void 0 : _c.user) === null || _d === void 0 ? void 0 : _d.name,
|
||||
fullyKiosk: this.isFully || false,
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
battery_level: (_f = (_e = window.fully) === null || _e === void 0 ? void 0 : _e.getBatteryLevel()) !== null && _f !== void 0 ? _f : (battery === null || battery === void 0 ? void 0 : battery.level) * 100,
|
||||
charging: (_h = (_g = window.fully) === null || _g === void 0 ? void 0 : _g.isPlugged()) !== null && _h !== void 0 ? _h : battery === null || battery === void 0 ? void 0 : battery.charging,
|
||||
darkMode: (_k = (_j = this.hass) === null || _j === void 0 ? void 0 : _j.themes) === null || _k === void 0 ? void 0 : _k.darkMode,
|
||||
userData: (_l = this.hass) === null || _l === void 0 ? void 0 : _l.user,
|
||||
ip_address: (_m = window.fully) === null || _m === void 0 ? void 0 : _m.getIp4Address(),
|
||||
},
|
||||
});
|
||||
};
|
||||
update();
|
||||
}
|
||||
do_navigate(path) {
|
||||
if (!path)
|
||||
return;
|
||||
history.pushState(null, "", path);
|
||||
fireEvent("location-changed", {}, ha_element());
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var name = "browser_mod";
|
||||
var version = "2.0.0b0";
|
||||
var description = "";
|
||||
@ -1088,7 +1130,7 @@ var pjson = {
|
||||
// FullyKioskMixin,
|
||||
// BrowserModMediaPlayerMixin,
|
||||
// ]) {
|
||||
class BrowserMod extends CameraMixin(MediaPlayerMixin(ScreenSaverMixin(RequireInteractMixin(ConnectionMixin(EventTarget))))) {
|
||||
class BrowserMod extends BrowserStateMixin(CameraMixin(MediaPlayerMixin(ScreenSaverMixin(RequireInteractMixin(ConnectionMixin(EventTarget)))))) {
|
||||
constructor() {
|
||||
super();
|
||||
this.entity_id = deviceID.replace("-", "_");
|
||||
|
@ -35,6 +35,5 @@ class BrowserModCamera(BrowserModEntity, Camera):
|
||||
|
||||
def camera_image(self, width=None, height=None):
|
||||
if "camera" not in self._data:
|
||||
LOGGER.error(self._data)
|
||||
return None
|
||||
return base64.b64decode(self._data["camera"].split(",")[-1])
|
||||
|
@ -128,8 +128,7 @@ async def async_setup_connection(hass):
|
||||
|
||||
if store.get_device(deviceID).enabled:
|
||||
dev = getDevice(hass, deviceID)
|
||||
dev.data.update(msg.get("data", {}))
|
||||
dev.coordinator.async_set_updated_data(dev.data)
|
||||
dev.update(hass, msg.get("data", {}))
|
||||
|
||||
async_register_command(hass, handle_connect)
|
||||
async_register_command(hass, handle_register)
|
||||
|
@ -21,77 +21,74 @@ class BrowserModDevice:
|
||||
""" """
|
||||
self.deviceID = deviceID
|
||||
self.coordinator = Coordinator(hass, deviceID)
|
||||
self.entities = []
|
||||
self.camera_entity = None
|
||||
self.entities = {}
|
||||
self.data = {}
|
||||
self.setup_sensors(hass)
|
||||
self.settings = {}
|
||||
self.connection = None
|
||||
|
||||
def update_settings(self, hass, settings):
|
||||
if settings.get("camera", False) and self.camera_entity is None:
|
||||
self.add_camera(hass)
|
||||
elif self.camera_entity and not settings.get("camera", False):
|
||||
self.remove_camera(hass)
|
||||
self.update_entities(hass)
|
||||
|
||||
def setup_sensors(self, hass):
|
||||
def update(self, hass, newData):
|
||||
self.data.update(newData)
|
||||
self.update_entities(hass)
|
||||
self.coordinator.async_set_updated_data(self.data)
|
||||
|
||||
def update_settings(self, hass, settings):
|
||||
self.settings = settings
|
||||
self.update_entities(hass)
|
||||
|
||||
def update_entities(self, hass):
|
||||
"""Create all entities associated with the device."""
|
||||
|
||||
coordinator = self.coordinator
|
||||
deviceID = self.deviceID
|
||||
|
||||
sensors = [
|
||||
("battery_level", "Browser battery", "%", "battery"),
|
||||
("path", "Browser path"),
|
||||
("userAgent", "Browser userAgent"),
|
||||
("visibility", "Browser visibility"),
|
||||
("currentUser", "Browser user"),
|
||||
("height", "Browser height", "px"),
|
||||
("width", "Browser width", "px"),
|
||||
]
|
||||
adder = hass.data[DOMAIN][DATA_ADDERS]["sensor"]
|
||||
new = [BrowserSensor(coordinator, deviceID, *s) for s in sensors]
|
||||
adder(new)
|
||||
self.entities += new
|
||||
def _assert_browser_sensor(type, name, *properties):
|
||||
if name in self.entities:
|
||||
return
|
||||
adder = hass.data[DOMAIN][DATA_ADDERS][type]
|
||||
cls = {"sensor": BrowserSensor, "binary_sensor": BrowserBinarySensor}[type]
|
||||
new = cls(coordinator, deviceID, name, *properties)
|
||||
adder([new])
|
||||
self.entities[name] = new
|
||||
|
||||
binary_sensors = [
|
||||
("charging", "Browser charging"),
|
||||
("darkMode", "Browser dark mode"),
|
||||
("fullyKiosk", "Browser FullyKiosk"),
|
||||
]
|
||||
adder = hass.data[DOMAIN][DATA_ADDERS]["binary_sensor"]
|
||||
new = [BrowserBinarySensor(coordinator, deviceID, *s) for s in binary_sensors]
|
||||
adder(new)
|
||||
self.entities += new
|
||||
_assert_browser_sensor("sensor", "path", "Browser path")
|
||||
_assert_browser_sensor("sensor", "visibility", "Browser visibility")
|
||||
_assert_browser_sensor("sensor", "userAgent", "Browser userAgent")
|
||||
_assert_browser_sensor("sensor", "currentUser", "Browser user")
|
||||
_assert_browser_sensor("sensor", "width", "Browser width", "px")
|
||||
_assert_browser_sensor("sensor", "height", "Browser height", "px")
|
||||
if self.data.get("browser", {}).get("battery_level", None) is not None:
|
||||
_assert_browser_sensor(
|
||||
"sensor", "battery_level", "Browser battery", "%", "battery"
|
||||
)
|
||||
|
||||
_assert_browser_sensor("binary_sensor", "darkMode", "Browser dark mode")
|
||||
_assert_browser_sensor("binary_sensor", "fullyKiosk", "Browser FullyKiosk")
|
||||
if self.data.get("browser", {}).get("charging", None) is not None:
|
||||
_assert_browser_sensor("binary_sensor", "charging", "Browser charging")
|
||||
|
||||
if "screen" not in self.entities:
|
||||
adder = hass.data[DOMAIN][DATA_ADDERS]["light"]
|
||||
new = [BrowserModLight(coordinator, deviceID, self)]
|
||||
adder(new)
|
||||
self.entities += new
|
||||
new = BrowserModLight(coordinator, deviceID, self)
|
||||
adder([new])
|
||||
self.entities["screen"] = new
|
||||
|
||||
if "player" not in self.entities:
|
||||
adder = hass.data[DOMAIN][DATA_ADDERS]["media_player"]
|
||||
new = [BrowserModPlayer(coordinator, deviceID, self)]
|
||||
adder(new)
|
||||
self.entities += new
|
||||
new = BrowserModPlayer(coordinator, deviceID, self)
|
||||
adder([new])
|
||||
self.entities["player"] = new
|
||||
|
||||
def add_camera(self, hass):
|
||||
if self.camera_entity is not None:
|
||||
return
|
||||
coordinator = self.coordinator
|
||||
deviceID = self.deviceID
|
||||
if "camera" not in self.entities and self.settings.get("camera"):
|
||||
adder = hass.data[DOMAIN][DATA_ADDERS]["camera"]
|
||||
self.camera_entity = BrowserModCamera(coordinator, deviceID)
|
||||
adder([self.camera_entity])
|
||||
self.entities.append(self.camera_entity)
|
||||
pass
|
||||
|
||||
def remove_camera(self, hass):
|
||||
if self.camera_entity is None:
|
||||
return
|
||||
new = BrowserModCamera(coordinator, deviceID)
|
||||
adder([new])
|
||||
self.entities["camera"] = new
|
||||
if "camera" in self.entities and not self.settings.get("camera"):
|
||||
er = entity_registry.async_get(hass)
|
||||
er.async_remove(self.camera_entity.entity_id)
|
||||
self.entities.remove(self.camera_entity)
|
||||
self.camera_entity = None
|
||||
pass
|
||||
er.async_remove(self.entities["camera"].entity_id)
|
||||
del self.entities["camera"]
|
||||
|
||||
def send(self, command, **kwargs):
|
||||
"""Send a command to this device."""
|
||||
@ -115,11 +112,10 @@ class BrowserModDevice:
|
||||
dr = device_registry.async_get(hass)
|
||||
er = entity_registry.async_get(hass)
|
||||
|
||||
for e in self.entities:
|
||||
for e in self.entities.items():
|
||||
er.async_remove(e.entity_id)
|
||||
|
||||
self.entities = []
|
||||
self.camera_entity = None
|
||||
self.entities = {}
|
||||
|
||||
device = dr.async_get_device({(DOMAIN, self.deviceID)})
|
||||
dr.async_remove_device(device.id)
|
||||
|
@ -22,10 +22,14 @@ class BrowserModEntity(CoordinatorEntity):
|
||||
|
||||
@property
|
||||
def device_info(self):
|
||||
config_url = {}
|
||||
if ip := self._data.get("browser", {}).get("ip_address"):
|
||||
config_url = {"configuration_url": f"http://{ip}:2323"}
|
||||
return {
|
||||
"identifiers": {(DOMAIN, self.deviceID)},
|
||||
"name": self.deviceID,
|
||||
"manufacturer": "Browser Mod",
|
||||
**config_url,
|
||||
}
|
||||
|
||||
@property
|
||||
|
@ -1,20 +1,21 @@
|
||||
import { fireEvent } from "card-tools/src/event";
|
||||
import { ha_element } from "card-tools/src/hass";
|
||||
|
||||
export const BrowserModBrowserMixin = (C) =>
|
||||
class extends C {
|
||||
export const BrowserStateMixin = (SuperClass) => {
|
||||
return class BrowserStateMixinClass extends SuperClass {
|
||||
constructor() {
|
||||
super();
|
||||
document.addEventListener("visibilitychange", () => this.sensor_update());
|
||||
window.addEventListener("location-changed", () => this.sensor_update());
|
||||
|
||||
this.addEventListener("browser-mod-connected", () =>
|
||||
this.sensor_update()
|
||||
document.addEventListener("visibilitychange", () =>
|
||||
this._browser_state_update()
|
||||
);
|
||||
// window.setInterval(() => this.sensor_update(), 10000);
|
||||
window.addEventListener("location-changed", () =>
|
||||
this._browser_state_update()
|
||||
);
|
||||
|
||||
this.connectionPromise.then(() => this._browser_state_update());
|
||||
}
|
||||
|
||||
sensor_update() {
|
||||
_browser_state_update() {
|
||||
const update = async () => {
|
||||
const battery = (<any>navigator).getBattery?.();
|
||||
this.sendUpdate({
|
||||
@ -23,7 +24,7 @@ export const BrowserModBrowserMixin = (C) =>
|
||||
visibility: document.visibilityState,
|
||||
userAgent: navigator.userAgent,
|
||||
currentUser: this.hass?.user?.name,
|
||||
fullyKiosk: this.isFully,
|
||||
fullyKiosk: this.isFully || false,
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
battery_level:
|
||||
@ -31,7 +32,7 @@ export const BrowserModBrowserMixin = (C) =>
|
||||
charging: window.fully?.isPlugged() ?? battery?.charging,
|
||||
darkMode: this.hass?.themes?.darkMode,
|
||||
userData: this.hass?.user,
|
||||
// config: this.config,
|
||||
ip_address: window.fully?.getIp4Address(),
|
||||
},
|
||||
});
|
||||
};
|
||||
@ -44,3 +45,4 @@ export const BrowserModBrowserMixin = (C) =>
|
||||
fireEvent("location-changed", {}, ha_element());
|
||||
}
|
||||
};
|
||||
};
|
||||
|
@ -4,6 +4,9 @@ export const CameraMixin = (SuperClass) => {
|
||||
private _canvas;
|
||||
private _framerate;
|
||||
|
||||
// TODO: Enable WebRTC?
|
||||
// https://levelup.gitconnected.com/establishing-the-webrtc-connection-videochat-with-javascript-step-3-48d4ae0e9ea4
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._framerate = 2;
|
||||
|
@ -14,7 +14,7 @@ import { RequireInteractMixin } from "./require-interact";
|
||||
import { FullyKioskMixin } from "./fullyKiosk";
|
||||
import { BrowserModScreensaverMixin } from "./screensaver";
|
||||
import { BrowserModPopupsMixin } from "./popups";
|
||||
import { BrowserModBrowserMixin } from "./browser";
|
||||
import { BrowserStateMixin } from "./browser";
|
||||
import pjson from "../../package.json";
|
||||
|
||||
const ext = (baseClass, mixins) =>
|
||||
@ -28,10 +28,12 @@ const ext = (baseClass, mixins) =>
|
||||
// FullyKioskMixin,
|
||||
// BrowserModMediaPlayerMixin,
|
||||
// ]) {
|
||||
export class BrowserMod extends CameraMixin(
|
||||
export class BrowserMod extends BrowserStateMixin(
|
||||
CameraMixin(
|
||||
MediaPlayerMixin(
|
||||
ScreenSaverMixin(RequireInteractMixin(ConnectionMixin(EventTarget)))
|
||||
)
|
||||
)
|
||||
) {
|
||||
constructor() {
|
||||
super();
|
||||
|
Loading…
x
Reference in New Issue
Block a user