iobroker.nspanel-lovelace-ui
Version:
NsPanel Lovelace UI is a Firmware for the nextion screen inside of NSPanel in the Design of Lovelace UI Design.
389 lines (388 loc) • 13.4 kB
JavaScript
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var controller_exports = {};
__export(controller_exports, {
Controller: () => Controller
});
module.exports = __toCommonJS(controller_exports);
var Library = __toESM(require("../classes/library"));
var import_states_controller = require("./states-controller");
var Panel = __toESM(require("./panel"));
var import_definition = require("../const/definition");
var import_system_notifications = require("../classes/system-notifications");
var import_tools = require("../const/tools");
var import_axios = __toESM(require("axios"));
var import_Color = require("../const/Color");
import_axios.default.defaults.timeout = 1e4;
class Controller extends Library.BaseClass {
mqttClient;
statesControler;
panels = [];
minuteLoopTimeout;
dateUpdateTimeout;
dailyIntervalTimeout;
dataCache = {};
systemNotification;
constructor(adapter, options) {
super(adapter, options.name);
import_Color.Color.setTheme(import_Color.Color.currentTheme);
this.adapter.controller = this;
this.mqttClient = options.mqttClient;
this.statesControler = new import_states_controller.StatesControler(this.adapter);
this.systemNotification = new import_system_notifications.SystemNotifications(this.adapter);
if (this.adapter.mqttServer) {
this.adapter.mqttServer.controller = this;
}
for (const panelConfig of options.panels) {
if (panelConfig === void 0) {
continue;
}
void this.addPanel(panelConfig);
}
this.log.debug(`${this.name} created`);
}
minuteLoop = async () => {
const minute = (/* @__PURE__ */ new Date()).getMinutes();
if (minute === 0) {
this.panels.forEach((panel) => {
panel.sendDimmode();
});
}
if (minute % 5 === 1) {
this.panels.forEach((panel) => {
panel.requestStatusTasmota();
});
}
await this.statesControler.setInternalState("///time", await this.getCurrentTime(), true);
const diff = 6e4 - Date.now() % 6e4 + 10;
if (this.unload) {
return;
}
this.minuteLoopTimeout = this.adapter.setTimeout(this.minuteLoop, diff);
};
/**
* Update Date every day at 0:00:01....
*
* @returns void
*/
dateUpdateLoop = async () => {
const d = /* @__PURE__ */ new Date();
d.setDate(d.getDate() + 1);
d.setHours(0, 0, 1);
const diff = d.getTime() - Date.now();
this.log.debug(`Set current Date with time: ${new Date(await this.getCurrentTime()).toString()}`);
await this.statesControler.setInternalState("///date", this.getCurrentTime(), true);
if (this.unload) {
return;
}
this.dateUpdateTimeout = this.adapter.setTimeout(this.dateUpdateLoop, diff);
};
getCurrentTime = async () => {
return new Promise((resolve) => resolve(Date.now()));
};
/**
* Handles internal commands based on the provided id and state.
*
* @param id - The identifier for the internal command.
* @param _state - The state associated with the command.
* @returns The value of the internal state or null if not applicable.
*/
onInternalCommand = async (id, _state) => {
if (!id.startsWith("///")) {
return null;
}
const token = id.split("///").pop();
switch (token) {
case "AdapterStoppedBoolean":
case "AdapterNoConnectionBoolean":
case "AdapterNoConnection":
case "AdapterStopped": {
if (this.dataCache[token] && this.dataCache[token].time < Date.now() - 5e3) {
delete this.dataCache[token];
}
let save = false;
if (!this.dataCache[token]) {
this.dataCache[token] = { time: Date.now(), data: {} };
save = true;
}
let list;
if (save) {
list = await this.adapter.getObjectViewAsync("system", "instance", {
startkey: `system.adapter`,
endkey: `system.adapter}`
});
this.dataCache[token].data[`system#view.instance`] = list;
} else {
list = this.dataCache[token].data[`system#view.instance`];
}
if (!list || !list.token) {
return null;
}
let total = 0;
let withProblems = 0;
for (const item of list.rows) {
const obj = item.value;
if (!obj.common.enabled || obj.common.mode !== "daemon") {
continue;
}
if (token === "AdapterStopped" || token === "AdapterStoppedBoolean") {
let state;
if (save) {
state = await this.adapter.getForeignStateAsync(`${item.id}.alive`);
this.dataCache[token].data[`${item.id}.alive`] = state;
} else {
state = this.dataCache[token].data[`${item.id}.alive`];
}
if (state && !state.val) {
withProblems++;
if (token === "AdapterStoppedBoolean") {
return true;
}
}
total++;
} else if (token === "AdapterNoConnection" || token === "AdapterNoConnectionBoolean") {
const nID = item.id.split(".").slice(2).join(".");
let state;
if (save) {
state = await this.adapter.getForeignStateAsync(`${nID}.info.connection`);
this.dataCache[token].data[`${nID}.info.connection`] = state;
} else {
state = this.dataCache[token].data[`${nID}.info.connection`];
}
if (state && !state.val) {
withProblems++;
if (token === "AdapterNoConnectionBoolean") {
return true;
}
}
total++;
}
}
if (token === "AdapterNoConnectionBoolean" || token === "AdapterStoppedBoolean") {
return false;
}
return `(${withProblems}/${total})`;
}
}
return null;
};
async init() {
await this.statesControler.setInternalState(
"///time",
await this.getCurrentTime(),
true,
{
name: "",
type: "number",
role: "value.time",
read: true,
write: false
},
this.getCurrentTime
);
await this.statesControler.setInternalState(
"///date",
await this.getCurrentTime(),
true,
{
name: "",
type: "number",
role: "value.time",
read: true,
write: false
},
this.getCurrentTime
);
await this.statesControler.setInternalState(
`///AdapterNoConnection`,
"",
true,
(0, import_tools.getInternalDefaults)("string", "text", false),
this.onInternalCommand
);
await this.statesControler.setInternalState(
`///AdapterStopped`,
"",
true,
(0, import_tools.getInternalDefaults)("string", "text", false),
this.onInternalCommand
);
await this.statesControler.setInternalState(
`///AdapterNoConnectionBoolean`,
true,
true,
(0, import_tools.getInternalDefaults)("boolean", "indicator", false),
this.onInternalCommand
);
await this.statesControler.setInternalState(
`///AdapterStoppedBoolean`,
true,
true,
(0, import_tools.getInternalDefaults)("boolean", "indicator", false),
this.onInternalCommand
);
await this.library.writedp(`panels`, void 0, import_definition.genericStateObjects.panel._channel);
void this.systemNotification.init();
void this.minuteLoop();
void this.dateUpdateLoop();
await this.getTasmotaVersion();
await this.getTFTVersion();
this.dailyIntervalTimeout = this.adapter.setInterval(this.dailyInterval, 24 * 60 * 60 * 1e3);
}
addPanel = async (panel) => {
let index = this.panels.findIndex((p) => p.topic === panel.topic);
if (index !== -1) {
this.adapter.testSuccessful = false;
this.adapter.log.error(`Panel ${panel.name} with topic ${panel.topic} already exists`);
return;
}
index = this.adapter.config.panels.findIndex((p) => p.topic === panel.topic);
if (index === -1) {
this.adapter.testSuccessful = false;
this.adapter.log.error(`Panel ${panel.name} with topic ${panel.topic} not found in config`);
return;
}
panel.name = this.adapter.config.panels[index].id;
panel.friendlyName = this.adapter.config.panels[index].name;
panel.controller = this;
const o = await this.adapter.getForeignObjectAsync(this.adapter.namespace);
if ((panel == null ? void 0 : panel.topic) && o && o.native && o.native.navigation) {
if (o.native.navigation[panel.topic] && o.native.navigation[panel.topic].useNavigation) {
panel.navigation = o.native.navigation[panel.topic].data;
}
}
const newPanel = new Panel.Panel(this.adapter, panel);
await this.adapter.delay(100);
if (await newPanel.isValid()) {
this.panels.push(newPanel);
await newPanel.init();
this.log.debug(`Panel ${newPanel.name} created`);
} else {
await newPanel.delete();
this.adapter.testSuccessful = false;
this.log.error(`Panel ${panel.name} has a invalid configuration.`);
}
};
removePanel = async (panel) => {
const index = this.panels.findIndex((p) => p.topic === panel.topic);
if (index !== -1) {
this.panels.splice(index, 1);
await panel.delete();
this.log.info(`Panel ${panel.topic} deleted`);
} else {
this.log.error(`Panel ${panel.topic} not found`);
}
};
mqttClientConnected = (id) => {
if (id === this.mqttClient.clientId) {
return true;
}
const index = this.panels.findIndex((p) => id.startsWith(this.library.cleandp(p.friendlyName)));
if (index !== -1) {
if (this.panels[index].initDone) {
this.panels[index].restartLoops();
return true;
}
}
return false;
};
async delete() {
await super.delete();
if (this.minuteLoopTimeout) {
this.adapter.clearTimeout(this.minuteLoopTimeout);
}
if (this.dateUpdateTimeout) {
this.adapter.clearTimeout(this.dateUpdateTimeout);
}
if (this.dailyIntervalTimeout) {
this.adapter.clearInterval(this.dailyIntervalTimeout);
}
if (this.systemNotification) {
await this.systemNotification.delete();
}
if (this.statesControler) {
await this.statesControler.delete();
}
for (const a of this.panels) {
if (a) {
await a.delete();
}
}
}
async notificationToPanel() {
if (!this.panels) {
return;
}
await this.statesControler.setInternalState("///Notifications", true, true);
}
dailyInterval = async () => {
await this.getTFTVersion();
await this.getTasmotaVersion();
};
async getTFTVersion() {
try {
const result = await import_axios.default.get(
"https://raw.githubusercontent.com/ticaki/ioBroker.nspanel-lovelace-ui/main/json/version.json"
);
if (result.status !== 200) {
this.log.warn(`Error getting TFT version: ${result.status}`);
return;
}
const version = this.adapter.config.useBetaTFT ? result.data["tft-beta"].split("_")[0] : result.data.tft.split("_")[0];
for (const p of this.panels) {
if (p) {
p.info.nspanel.onlineVersion = version;
}
}
} catch {
}
}
async getTasmotaVersion() {
const urlString = "https://api.github.com/repositories/80286288/releases/latest";
try {
const response = await (0, import_axios.default)(urlString, { headers: { "User-Agent": "ioBroker" } });
if (response && response.status === 200) {
const data = response.data;
const TasmotaTagName = data.tag_name;
const TasmotaVersionOnline = TasmotaTagName.replace(/v/i, "");
for (const p of this.panels) {
if (p) {
p.info.tasmota.onlineVersion = TasmotaVersionOnline;
}
}
}
} catch {
}
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Controller
});
//# sourceMappingURL=controller.js.map