diff --git a/README.md b/README.md index 1c8378b..74248a6 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,12 @@ Once this ioBroker.fully-mqtt adapter is tested accordingly and runs stable, I w Placeholder for the next version (at the beginning of the line): ### **WORK IN PROGRESS** --> + +### **WORK IN PROGRESS** + +- (Acgua) Fixed starting MQTT server +- (Acgua) Removed info log 'MQTT is not activated in adapter instance settings.' + ### 0.1.0 (2023-03-27) - (Acgua) **Breaking Change**: Using MQTT is required, and removed option to deactivate MQTT. Reasons: 1. requesting info thru REST API is redundant and simply not needed since MQTT is available, 2. It does not make sense to not use MQTT since it provides live updates of states. diff --git a/build/main.js b/build/main.js index 08e954a..b7fd0d3 100644 --- a/build/main.js +++ b/build/main.js @@ -49,7 +49,6 @@ class FullyMqtt extends utils.Adapter { this.cleanDeviceName = import_methods.cleanDeviceName.bind(this); this.getConfigValuePerKey = import_methods.getConfigValuePerKey.bind(this); this.isIpAddressValid = import_methods.isIpAddressValid.bind(this); - this.mqtt_useMqtt = false; this.restApi_inst = new import_restApi.RestApiFully(this); this.fullys = {}; this.disabledDeviceIds = []; @@ -68,10 +67,8 @@ class FullyMqtt extends utils.Adapter { this.log.error(`Adapter settings initialization failed. ---> Please check your adapter instance settings!`); return; } - if (this.mqtt_useMqtt) { - this.mqtt_Server = new import_mqtt_server.MqttServer(this); - this.mqtt_Server.start(); - } + this.mqtt_Server = new import_mqtt_server.MqttServer(this); + this.mqtt_Server.start(); for (const ip in this.fullys) { await this.main(this.fullys[ip]); } @@ -242,12 +239,6 @@ class FullyMqtt extends utils.Adapter { logConfig.restPassword = "(hidden)"; this.log.debug(`Final Config: ${JSON.stringify(logConfig)}`); if (lpDevice.enabled) { - if (lpDevice.useMQTT) { - this.mqtt_useMqtt = true; - this.log.info(`${finalDevice.name} (${finalDevice.ip}) MQTT is activated in adapter instance settings.`); - } else { - this.log.info(`${finalDevice.name} (${finalDevice.ip}) MQTT is not activated in adapter instance settings.`); - } this.fullys[finalDevice.ip] = finalDevice; this.activeDeviceIPs.push(lpDevice.ip); this.log.info(`\u{1F5F8} ${finalDevice.name} (${finalDevice.ip}): Config successfully verified.`); diff --git a/build/main.js.map b/build/main.js.map index a1c37b9..4cb6a22 100644 --- a/build/main.js.map +++ b/build/main.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/main.ts"], - "sourcesContent": ["/**\r\n * -------------------------------------------------------------------\r\n * ioBroker Fully Browser MQTT Adapter\r\n * @github https://github.com/Acgua/ioBroker.fully-mqtt\r\n * @forum https://forum.iobroker.net/topic/63705/\r\n * @author Acgua \r\n * @license Apache License 2.0\r\n * -------------------------------------------------------------------\r\n */\r\n\r\n/**\r\n * For all imported NPM modules, open console, change dir for example to \"C:\\iobroker\\node_modules\\ioBroker.fully-mqtt\\\"\r\n * and execute \"npm install \", e.g., npm install axios\r\n */\r\nimport * as utils from '@iobroker/adapter-core';\r\nimport { CONST } from './lib/constants';\r\nimport { ICmds, IDevice } from './lib/interfaces';\r\nimport { cleanDeviceName, err2Str, getConfigValuePerKey, isEmpty, isIpAddressValid, wait } from './lib/methods';\r\nimport { MqttServer } from './lib/mqtt-server';\r\nimport { RestApiFully } from './lib/restApi';\r\n\r\n/**\r\n * Main ioBroker Adapter Class\r\n */\r\nexport class FullyMqtt extends utils.Adapter {\r\n // Imported methods from ./lib/methods\r\n public err2Str = err2Str.bind(this);\r\n public isEmpty = isEmpty.bind(this);\r\n public wait = wait.bind(this);\r\n public cleanDeviceName = cleanDeviceName.bind(this);\r\n public getConfigValuePerKey = getConfigValuePerKey.bind(this);\r\n public isIpAddressValid = isIpAddressValid.bind(this);\r\n // MQTT\r\n private mqtt_Server: MqttServer | undefined;\r\n public mqtt_useMqtt: true | false = false; // Is use of MQTT activated per adapter settings (each line of fully devices is checked)\r\n\r\n // REST API\r\n private restApi_inst = new RestApiFully(this); // RestApi Class Instance\r\n\r\n /**\r\n * Active Fullys: IP as key, and object per IDevice\r\n * {\r\n * '192.168.10.20': {name: 'Tablet Kitchen', id:'Tablet-Kitchen', ip:'192.168.10.20', ...},\r\n * '192.168.10.30': {name: 'Tablet Hallway', id:'Tablet-Hallway', ip:'192.168.10.30', ...},\r\n * }\r\n * Use this.getFullyPerKey() to get fully object per provided key\r\n */\r\n public fullys: { [ip: string]: IDevice } = {};\r\n\r\n // array of device ids, which are not activated\r\n public disabledDeviceIds = [] as string[];\r\n // All active IP addresses\r\n public activeDeviceIPs = [] as string[]; // for MQTT server to verify IP\r\n\r\n // Has onAliveChange() ever been called before?\r\n private onAliveChange_EverBeenCalledBefore = false;\r\n\r\n /**\r\n * Constructor\r\n */\r\n public constructor(options: Partial = {}) {\r\n super({ ...options, name: 'fully-mqtt' });\r\n\r\n this.on('ready', this.onReady.bind(this));\r\n this.on('stateChange', this.onStateChange.bind(this));\r\n // this.on('objectChange', this.onObjectChange.bind(this));\r\n // this.on('message', this.onMessage.bind(this));\r\n this.on('unload', this.onUnload.bind(this));\r\n }\r\n\r\n /**\r\n * Is called when databases are connected and adapter received configuration.\r\n */\r\n private async onReady(): Promise {\r\n try {\r\n /**\r\n * Set the connection indicator to false during startup\r\n */\r\n this.setState('info.connection', { val: false, ack: true });\r\n\r\n /**\r\n * Init configuration\r\n */\r\n if (await this.initConfig()) {\r\n this.log.debug(`Adapter settings successfully verified and initialized.`);\r\n } else {\r\n this.log.error(`Adapter settings initialization failed. ---> Please check your adapter instance settings!`);\r\n return;\r\n }\r\n\r\n /**\r\n * Start MQTT Server\r\n */\r\n if (this.mqtt_useMqtt) {\r\n this.mqtt_Server = new MqttServer(this);\r\n this.mqtt_Server.start();\r\n }\r\n\r\n /**\r\n * Call main() for each device\r\n */\r\n for (const ip in this.fullys) {\r\n await this.main(this.fullys[ip]);\r\n }\r\n\r\n /**\r\n * Delete device object tree(s) if deleted or renamed in config\r\n */\r\n this.deleteRemovedDeviceObjects();\r\n } catch (e) {\r\n this.log.error(this.err2Str(e));\r\n return;\r\n }\r\n }\r\n\r\n /**\r\n * main function for each Fully Browser Device\r\n * @param device Fully Browser Device Object\r\n */\r\n private async main(device: IDevice): Promise {\r\n try {\r\n this.log.debug(`Start main() - ${device.name} (${device.ip})\u2026`);\r\n\r\n /**\r\n * Create device object(s)\r\n */\r\n // Device and Info object\r\n await this.setObjectNotExistsAsync(device.id, {\r\n type: 'device',\r\n common: {\r\n name: device.name,\r\n //@ts-expect-error - Object \"statusStates\" is needed for status, error is: Object literal may only specify known properties, and 'statusStates' does not exist in type 'DeviceCommon'.ts(2345)\r\n statusStates: { onlineId: `${this.namespace}.${device.id}.alive` },\r\n },\r\n native: {},\r\n });\r\n await this.setObjectNotExistsAsync(device.id + '.Info', { type: 'channel', common: { name: 'Device Information' }, native: {} });\r\n\r\n // Alive and info update\r\n await this.setObjectNotExistsAsync(device.id + '.alive', {\r\n type: 'state',\r\n common: {\r\n name: 'Is Fully alive?',\r\n desc: 'If Fully Browser is alive or not',\r\n type: 'boolean',\r\n role: 'indicator.reachable',\r\n icon: 'data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iTXVpU3ZnSWNvbi1yb290IE11aVN2Z0ljb24tZm9udFNpemVNZWRpdW0gaWNvbk93biBjc3MtdnViYnV2IiBmb2N1c2FibGU9ImZhbHNlIiBhcmlhLWhpZGRlbj0idHJ1ZSIgdmlld0JveD0iMCAwIDI0IDI0IiBkYXRhLXRlc3RpZD0iV2lmaUljb24iPjxwYXRoIGQ9Im0xIDkgMiAyYzQuOTctNC45NyAxMy4wMy00Ljk3IDE4IDBsMi0yQzE2LjkzIDIuOTMgNy4wOCAyLjkzIDEgOXptOCA4IDMgMyAzLTNjLTEuNjUtMS42Ni00LjM0LTEuNjYtNiAwem0tNC00IDIgMmMyLjc2LTIuNzYgNy4yNC0yLjc2IDEwIDBsMi0yQzE1LjE0IDkuMTQgOC44NyA5LjE0IDUgMTN6Ij48L3BhdGg+PC9zdmc+',\r\n read: true,\r\n write: false,\r\n },\r\n native: {},\r\n });\r\n await this.setObjectNotExistsAsync(device.id + '.lastInfoUpdate', { type: 'state', common: { name: 'Last information update', desc: 'Date/time of last information update from Fully Browser', type: 'number', role: 'value.time', read: true, write: false }, native: {} });\r\n\r\n // REST API Commands Objects\r\n await this.setObjectNotExistsAsync(device.id + '.Commands', { type: 'channel', common: { name: 'Commands (REST API)' }, native: {} });\r\n const allCommands = CONST.cmds.concat(CONST.cmdsSwitches); // join both arrays\r\n for (const cmdObj of allCommands) {\r\n let lpRole = '';\r\n if (cmdObj.type === 'boolean') lpRole = 'button';\r\n if (cmdObj.type === 'string') lpRole = 'text';\r\n if (cmdObj.type === 'number') lpRole = 'value';\r\n if (cmdObj.cmdOn && cmdObj.cmdOff) lpRole = 'switch';\r\n await this.setObjectNotExistsAsync(device.id + '.Commands.' + cmdObj.id, { type: 'state', common: { name: 'Command: ' + cmdObj.name, type: cmdObj.type, role: lpRole, read: true, write: true }, native: {} });\r\n }\r\n\r\n // Create MQTT Events Objects\r\n // More states are created once a new Event is received.\r\n await this.setObjectNotExistsAsync(device.id + '.Events', { type: 'channel', common: { name: 'MQTT Events' }, native: {} });\r\n for (const event of CONST.mqttEvents) {\r\n await this.setObjectNotExistsAsync(device.id + '.Events.' + event, { type: 'state', common: { name: 'MQTT Event: ' + event, type: 'boolean', role: 'switch', read: true, write: false }, native: {} });\r\n }\r\n\r\n /**\r\n * REST API: Subscribe to command state changes\r\n */\r\n await this.subscribeStatesAsync(device.id + '.Commands.*');\r\n } catch (e) {\r\n this.log.error(this.err2Str(e));\r\n return;\r\n }\r\n }\r\n\r\n /**\r\n * Delete device objects if device was (a) renamed or (b) deleted from devices table in adapter settings.\r\n * However, do not delete if it was just set inactive in table.\r\n */\r\n private async deleteRemovedDeviceObjects(): Promise {\r\n try {\r\n // Get string array of all adapter objects: ['fully-mqtt.0.info', 'fully-mqtt.0.info.connection', ...];\r\n const adapterObjectsIds: string[] = Object.keys(await this.getAdapterObjectsAsync());\r\n\r\n // Get all existing fully device ids of iobroker adapter objects in array: 'fully-mqtt.0.Tablet-Kitchen' -> 'Tablet-Kitchen', 'fully-mqtt.0.Tablet-Hallway' -> 'Tablet-Hallway', etc.\r\n const allObjectDeviceIds: Array = [];\r\n for (const objectId of adapterObjectsIds) {\r\n const deviceId = objectId.split('.')[2]; // e.g. 'Tablet-Kitchen'\r\n // Ignore fully-mqtt.0.info tree (which includes fully-mqtt.0.info.connection, ...). Add more to ignore as needed in the future...\r\n if (['info'].includes(deviceId)) {\r\n this.log.silly(`Cleanup: Ignore non device related state ${objectId}.`);\r\n } else {\r\n if (!allObjectDeviceIds.includes(deviceId)) allObjectDeviceIds.push(deviceId);\r\n }\r\n }\r\n\r\n // process all adapter object devices ['Tablet-Kitchen', 'Tablet-Hallway', ...] accordingly\r\n for (const id of allObjectDeviceIds) {\r\n // We handle both disabled devices and enabled devices\r\n const allConfigDeviceIds = this.disabledDeviceIds; // add all disabled ids first\r\n // now add all active ones\r\n for (const ip in this.fullys) {\r\n allConfigDeviceIds.push(this.fullys[ip].id);\r\n }\r\n\r\n if (!allConfigDeviceIds.includes(id)) {\r\n await this.delObjectAsync(id, { recursive: true });\r\n this.log.info(`Cleanup: Deleted no longer defined device objects of '${id}'.`);\r\n }\r\n }\r\n } catch (e) {\r\n this.log.error(this.err2Str(e));\r\n return;\r\n }\r\n }\r\n\r\n /**\r\n * Verify adapter instance settings\r\n */\r\n private async initConfig(): Promise {\r\n try {\r\n /*************************\r\n * MQTT Fields\r\n *************************/\r\n if (this.isEmpty(this.config.mqttPort) || this.config.mqttPort < 1 || this.config.mqttPort > 65535) {\r\n this.log.warn(`Adapter instance settings: MQTT Port ${this.config.mqttPort} is not allowed, set to default of 1886`);\r\n this.config.mqttPort = 1886;\r\n }\r\n if (this.isEmpty(this.config.mqttPublishedInfoDelay) || this.config.mqttPublishedInfoDelay < 2 || this.config.mqttPublishedInfoDelay > 120) {\r\n this.log.warn(`Adapter instance settings: MQTT Publish Info Delay of ${this.config.mqttPublishedInfoDelay}s is not allowed, set to default of 30s`);\r\n this.config.mqttPublishedInfoDelay = 30;\r\n }\r\n\r\n /*************************\r\n * REST API Fields\r\n *************************/\r\n if (this.isEmpty(this.config.restTimeout) || this.config.restTimeout < 500 || this.config.restTimeout > 15000) {\r\n this.log.warn(`Adapter instance settings: REST API timeout of ${this.config.restTimeout} ms is not allowed, set to default of 6000ms`);\r\n this.config.restTimeout = 6000;\r\n }\r\n\r\n /*************************\r\n * Table Devices\r\n *************************/\r\n if (this.isEmpty(this.config.tableDevices)) {\r\n this.log.error(`No Fully devices defined in adapter instance settings!`);\r\n return false;\r\n }\r\n const deviceIds: string[] = []; // to check for duplicate device ids\r\n const deviceIPs: string[] = []; // to check for duplicate device IPs\r\n for (let i = 0; i < this.config.tableDevices.length; i++) {\r\n const lpDevice = this.config.tableDevices[i];\r\n const finalDevice: IDevice = {\r\n name: '',\r\n id: '',\r\n ip: '',\r\n mqttInfoObjectsCreated: false,\r\n mqttInfoKeys: [],\r\n restProtocol: 'http',\r\n restPort: 0,\r\n restPassword: '',\r\n lastSeen: 0, // timestamp\r\n isAlive: false,\r\n };\r\n\r\n // name\r\n if (this.isEmpty(lpDevice.name)) {\r\n this.log.error(`Provided device name \"${lpDevice.name}\" is empty!`);\r\n return false;\r\n }\r\n finalDevice.name = lpDevice.name.trim();\r\n\r\n // id\r\n finalDevice.id = this.cleanDeviceName(lpDevice.name);\r\n if (finalDevice.id.length < 1) {\r\n this.log.error(`Provided device name \"${lpDevice.name}\" is too short and/or has invalid characters!`);\r\n return false;\r\n }\r\n if (deviceIds.includes(finalDevice.id)) {\r\n this.log.error(`Device \"${finalDevice.name}\" -> id:\"${finalDevice.id}\" is used for more than once device.`);\r\n return false;\r\n } else {\r\n deviceIds.push(finalDevice.id);\r\n }\r\n\r\n // REST Protocol (http/https)\r\n if (lpDevice.restProtocol !== 'http' && lpDevice.restProtocol !== 'https') {\r\n this.log.warn(`${finalDevice.name}: REST API Protocol is empty, set to http as default.`);\r\n finalDevice.restProtocol = 'http';\r\n } else {\r\n finalDevice.restProtocol = lpDevice.restProtocol;\r\n }\r\n\r\n // IP Address\r\n if (!this.isIpAddressValid(lpDevice.ip)) {\r\n this.log.error(`${finalDevice.name}: Provided IP address \"${lpDevice.ip}\" is not valid!`);\r\n return false;\r\n }\r\n if (deviceIPs.includes(lpDevice.ip)) {\r\n this.log.error(`Device \"${finalDevice.name}\" -> IP:\"${lpDevice.ip}\" is used for more than once device.`);\r\n return false;\r\n } else {\r\n deviceIPs.push(lpDevice.ip);\r\n finalDevice.ip = lpDevice.ip;\r\n }\r\n\r\n // REST Port\r\n if (isNaN(lpDevice.restPort) || lpDevice.restPort < 0 || lpDevice.restPort > 65535) {\r\n this.log.error(`Adapter config Fully port number ${lpDevice.restPort} is not valid, should be >= 0 and < 65536.`);\r\n return false;\r\n } else {\r\n finalDevice.restPort = Math.round(lpDevice.restPort);\r\n }\r\n // REST Password\r\n if (isEmpty(lpDevice.restPassword)) {\r\n this.log.error(`Remote Admin (REST API) Password must not be empty!`);\r\n return false;\r\n } else {\r\n finalDevice.restPassword = lpDevice.restPassword;\r\n }\r\n\r\n const logConfig = { ...finalDevice }; // copy object using spread\r\n logConfig.restPassword = '(hidden)'; // do not show password in log !\r\n this.log.debug(`Final Config: ${JSON.stringify(logConfig)}`);\r\n if (lpDevice.enabled) {\r\n // if MQTT is activated, set variable to true\r\n if (lpDevice.useMQTT) {\r\n this.mqtt_useMqtt = true;\r\n this.log.info(`${finalDevice.name} (${finalDevice.ip}) MQTT is activated in adapter instance settings.`);\r\n } else {\r\n this.log.info(`${finalDevice.name} (${finalDevice.ip}) MQTT is not activated in adapter instance settings.`);\r\n }\r\n\r\n // Finalize\r\n\r\n this.fullys[finalDevice.ip] = finalDevice;\r\n this.activeDeviceIPs.push(lpDevice.ip); // global array for all active IPs\r\n this.log.info(`\uD83D\uDDF8 ${finalDevice.name} (${finalDevice.ip}): Config successfully verified.`);\r\n } else {\r\n // Skip if not enabled. (but we did verification anyway!)\r\n this.disabledDeviceIds.push(finalDevice.id);\r\n this.log.debug(`Device ${finalDevice.name} (${finalDevice.ip}) is not enabled, so skip it.`);\r\n continue;\r\n }\r\n }\r\n\r\n if (Object.keys(this.fullys).length === 0) {\r\n this.log.error(`No active devices with correct configuration found.`);\r\n return false;\r\n }\r\n return true;\r\n } catch (e) {\r\n this.log.error(this.err2Str(e));\r\n return false;\r\n }\r\n }\r\n\r\n /**\r\n * On Alive Changes\r\n * for both REST API and MQTT\r\n */\r\n public async onAliveChange(source: 'MQTT' | 'REST', ip: string, isAlive: true | false, msg: string): Promise {\r\n try {\r\n const prevIsAlive = this.fullys[ip].isAlive;\r\n this.fullys[ip].isAlive = isAlive;\r\n\r\n // Has this function ever been called before? If adapter is restarted, we ensure log, etc.\r\n const calledBefore = this.onAliveChange_EverBeenCalledBefore; // Keep old value\r\n this.onAliveChange_EverBeenCalledBefore = true; // Now it was called\r\n\r\n /***********\r\n * 1 - Fully Device\r\n ***********/\r\n // if alive status changed\r\n if ((!calledBefore && isAlive === true) || prevIsAlive !== isAlive) {\r\n // Set Device isAlive Status - we could also use setStateChanged()...\r\n this.setState(this.fullys[ip].id + '.alive', { val: isAlive, ack: true });\r\n\r\n // log\r\n if (isAlive) {\r\n this.log.info(`${this.fullys[ip].name} is alive (${source}: ${msg})`);\r\n } else {\r\n this.log.warn(`${this.fullys[ip].name} is not alive! (${source}: ${msg})`);\r\n }\r\n } else {\r\n // No change\r\n }\r\n\r\n /***********\r\n * 2 - Adapter Connection indicator\r\n ***********/\r\n let countAll = 0;\r\n let countAlive = 0;\r\n for (const lpIpAddr in this.fullys) {\r\n countAll++;\r\n if (this.fullys[lpIpAddr].isAlive) {\r\n countAlive++;\r\n }\r\n }\r\n let areAllAlive = false;\r\n if (countAll > 0 && countAll === countAlive) areAllAlive = true;\r\n this.setStateChanged('info.connection', { val: areAllAlive, ack: true });\r\n } catch (e) {\r\n this.log.error(this.err2Str(e));\r\n return;\r\n }\r\n }\r\n\r\n /**\r\n * MQTT: once new device info packet is coming in\r\n */\r\n public async onMqttInfo(obj: { clientId: string; ip: string; topic: string; infoObj: { [k: string]: any } }): Promise {\r\n try {\r\n // log\r\n this.log.debug(`[MQTT]\uD83D\uDCE1 ${this.fullys[obj.ip].name} published info, topic: ${obj.topic}`);\r\n //this.log.debug(`[MQTT] Client ${obj.ip} Publish Info: Details: ${JSON.stringify(obj.infoObj)}`);\r\n\r\n // Create info objects if not yet existing\r\n const formerInfoKeysLength: number = this.fullys[obj.ip].mqttInfoKeys.length;\r\n const newInfoKeysAdded: string[] = [];\r\n for (const key in obj.infoObj) {\r\n const val = obj.infoObj[key];\r\n const valType = typeof val;\r\n // only accept certain types\r\n if (valType !== 'string' && valType !== 'boolean' && valType !== 'object' && valType !== 'number') {\r\n this.log.warn(`[MQTT] ${this.fullys[obj.ip].name}: Unknown type ${valType} of key '${key}' in info object`);\r\n continue;\r\n }\r\n // Create info object if not yet seen - this check is used for increasing performance by not unnesserily call setObjectNotExistsAsync() every time new info package comes in\r\n if (!this.fullys[obj.ip].mqttInfoKeys.includes(key)) {\r\n this.fullys[obj.ip].mqttInfoKeys.push(key);\r\n newInfoKeysAdded.push(key);\r\n await this.setObjectNotExistsAsync(`${this.fullys[obj.ip].id}.Info.${key}`, { type: 'state', common: { name: 'Info: ' + key, type: valType, role: 'value', read: true, write: false }, native: {} });\r\n }\r\n }\r\n if (formerInfoKeysLength === 0) this.log.debug(`[MQTT] ${this.fullys[obj.ip].name}: Initially create states for ${newInfoKeysAdded.length} info items (if not yet existing)`);\r\n if (formerInfoKeysLength > 0 && newInfoKeysAdded.length > 0) this.log.info(`[MQTT] ${this.fullys[obj.ip].name}: Created new info object(s) as not seen before (if object(s) did not exist): ${newInfoKeysAdded.join(', ')}`);\r\n\r\n // Set info objects\r\n for (const key in obj.infoObj) {\r\n const newVal = typeof obj.infoObj[key] === 'object' ? JSON.stringify(obj.infoObj[key]) : obj.infoObj[key]; // https://forum.iobroker.net/post/628870 - https://forum.iobroker.net/post/960260\r\n if (this.config.mqttUpdateUnchangedObjects) {\r\n this.setState(`${this.fullys[obj.ip].id}.Info.${key}`, { val: newVal, ack: true });\r\n } else {\r\n this.setStateChanged(`${this.fullys[obj.ip].id}.Info.${key}`, { val: newVal, ack: true });\r\n }\r\n }\r\n this.setState(this.fullys[obj.ip].id + '.lastInfoUpdate', { val: Date.now(), ack: true });\r\n this.setState(this.fullys[obj.ip].id + '.alive', { val: true, ack: true });\r\n } catch (e) {\r\n this.log.error(this.err2Str(e));\r\n return;\r\n }\r\n }\r\n\r\n /**\r\n * MQTT: once new event packet is coming in\r\n */\r\n public async onMqttEvent(obj: { clientId: string; ip: string; topic: string; cmd: string }): Promise {\r\n try {\r\n // log\r\n this.log.debug(`[MQTT] \uD83D\uDCE1 ${this.fullys[obj.ip].name} published event, topic: ${obj.topic}, cmd: ${obj.cmd}`);\r\n\r\n /**\r\n * Set Event State\r\n */\r\n const pthEvent = `${this.fullys[obj.ip].id}.Events.${obj.cmd}`;\r\n if (!(await this.getObjectAsync(pthEvent))) {\r\n this.log.info(`[MQTT] ${this.fullys[obj.ip].name}: Event ${obj.cmd} received but state ${pthEvent} does not exist, so we create it first`);\r\n await this.setObjectNotExistsAsync(pthEvent, { type: 'state', common: { name: 'MQTT Event: ' + obj.cmd, type: 'boolean', role: 'switch', read: true, write: false }, native: {} });\r\n }\r\n this.setState(pthEvent, { val: true, ack: true });\r\n\r\n /**\r\n * Confirm Command state(s) with ack: true\r\n */\r\n const pthCmd = this.fullys[obj.ip].id + '.Commands';\r\n\r\n // Check if it is a switch with MQTT commands connected\r\n const idx = this.getIndexFromConf(CONST.cmdsSwitches, ['mqttOn', 'mqttOff'], obj.cmd);\r\n if (idx !== -1) {\r\n // We have a switch\r\n const conf = CONST.cmdsSwitches[idx]; // the found line from config array\r\n const onOrOffCmd = obj.cmd === conf.mqttOn ? true : false;\r\n await this.setStateAsync(`${pthCmd}.${conf.id}`, { val: onOrOffCmd, ack: true });\r\n await this.setStateAsync(`${pthCmd}.${conf.cmdOn}`, { val: onOrOffCmd, ack: true });\r\n await this.setStateAsync(`${pthCmd}.${conf.cmdOff}`, { val: !onOrOffCmd, ack: true });\r\n } else {\r\n // No switch\r\n const idx = this.getIndexFromConf(CONST.cmds, ['id'], obj.cmd);\r\n if (idx !== -1 && CONST.cmds[idx].type === 'boolean') {\r\n // We have a button, so set it to true\r\n await this.setStateAsync(`${pthCmd}.${obj.cmd}`, { val: true, ack: true });\r\n } else {\r\n this.log.silly(`[MQTT] ${this.fullys[obj.ip].name}: Event cmd ${obj.cmd} - no REST API command is existing, so skip confirmation with with ack:true`);\r\n }\r\n }\r\n } catch (e) {\r\n this.log.error(this.err2Str(e));\r\n return;\r\n }\r\n }\r\n\r\n /**\r\n * Called once a subscribed state changes.\r\n * Ready once subscribeStatesAsync() is called...\r\n * @param id - e.g. \"fully-mqtt.0.Tablet-Bathroom.Commands.screenSwitch\"\r\n * @param stateObj - e.g. { val: true, ack: false, ts: 123456789, q: 0, lc: 123456789 }\r\n */\r\n private async onStateChange(stateId: string, stateObj: ioBroker.State | null | undefined): Promise {\r\n try {\r\n if (!stateObj) return; // state was deleted, we disregard...\r\n if (stateObj.ack) return; // ignore ack:true\r\n const idSplit = stateId.split('.');\r\n const deviceId = idSplit[2]; // \"Tablet-Bathroom\"\r\n const channel = idSplit[3]; // \"Commands\"\r\n const cmd = idSplit[4]; // \"screenSwitch\"\r\n const pth = deviceId + '.' + channel; // Tablet-Bathroom.Commands\r\n /**\r\n * Commands\r\n */\r\n if (channel === 'Commands') {\r\n this.log.debug(`state ${stateId} changed: ${stateObj.val} (ack = ${stateObj.ack})`);\r\n // Get device object\r\n const fully = this.getFullyByKey('id', deviceId);\r\n if (!fully) throw `Fully object for deviceId '${deviceId}' not found!`;\r\n\r\n let cmdToSend: string | undefined = cmd; // Command to send to Fully\r\n let switchConf: undefined | ICmds = undefined; // Config line of switch\r\n\r\n /****************\r\n * Check if it is a switch state cmd, like 'screenSwitch'\r\n ****************/\r\n const idxSw = this.getIndexFromConf(CONST.cmdsSwitches, ['id'], cmd);\r\n if (idxSw !== -1) {\r\n // It is a switch\r\n switchConf = CONST.cmdsSwitches[idxSw]; // the found line from config array\r\n cmdToSend = stateObj.val ? switchConf.cmdOn : switchConf.cmdOff;\r\n } else {\r\n // Not a switch.\r\n // If val is false, we disregard, since it is a button only\r\n if (!stateObj.val) return;\r\n }\r\n if (!cmdToSend) throw `onStateChange() - ${stateId}: fullyCmd could not be determined!`;\r\n\r\n /**\r\n * Send Command\r\n */\r\n const sendCommand = await this.restApi_inst.sendCmd(fully, cmdToSend, stateObj.val);\r\n if (sendCommand) {\r\n this.log.info(`${fully.name}: ${cmd} successfully set to ${stateObj.val}`);\r\n /**\r\n * Confirm with ack:true\r\n */\r\n if (switchConf !== undefined) {\r\n // it is a switch\r\n const onOrOffCmdVal = cmd === switchConf.cmdOn ? true : false;\r\n await this.setStateAsync(`${pth}.${switchConf.id}`, { val: onOrOffCmdVal, ack: true });\r\n await this.setStateAsync(`${pth}.${switchConf.cmdOn}`, { val: onOrOffCmdVal, ack: true });\r\n await this.setStateAsync(`${pth}.${switchConf.cmdOff}`, { val: !onOrOffCmdVal, ack: true });\r\n } else {\r\n // No switch\r\n if (typeof stateObj.val === 'boolean') {\r\n const idx = this.getIndexFromConf(CONST.cmds, ['id'], cmd);\r\n if (idx !== -1) {\r\n if (CONST.cmds[idx].type === 'boolean') {\r\n // Is a button\r\n await this.setStateAsync(stateId, { val: true, ack: true });\r\n } else {\r\n // This should actually not happen, as we just define buttons in commands, but anyway\r\n this.log.warn(`${fully.name}: ${stateId} - val: ${stateObj.val} is boolean, but cmd ${cmd} is not defined in CONF`);\r\n await this.setStateAsync(stateId, { val: stateObj.val, ack: true });\r\n }\r\n } else {\r\n this.log.warn(`${fully.name}: ${stateId} - val: ${stateObj.val}, cmd ${cmd} is not defined in CONF`);\r\n }\r\n } else {\r\n // Non-boolean, so just set val with ack:true...\r\n await this.setStateAsync(stateId, { val: stateObj.val, ack: true });\r\n }\r\n }\r\n } else {\r\n // log, more log lines were already published by this.restApi_inst.sendCmd()\r\n this.log.debug(`${fully.name}: restApiSendCmd() was not successful (${stateId})`);\r\n }\r\n }\r\n } catch (e) {\r\n this.log.error(this.err2Str(e));\r\n return;\r\n }\r\n }\r\n\r\n /**\r\n * Get Fully Object per provided key and value\r\n * {\r\n * '192.168.10.20': {name: 'Tablet Kitchen', id:'Tablet-Kitchen', ip:'192.168.10.20', ...},\r\n * '192.168.10.30': {name: 'Tablet Hallway', id:'Tablet-Hallway', ip:'192.168.10.30', ...},\r\n * }\r\n * getFullyByKey('id', 'Tablet-Hallway') will return the second object...\r\n * @param keyId - e.g. 'id', 'name', ...\r\n * @param value - e.g. 'Tablet Hallway', ...\r\n * @returns - fully object or false if not found\r\n */\r\n private getFullyByKey(keyId: string, value: any): IDevice | false {\r\n for (const ip in this.fullys) {\r\n if (keyId in this.fullys[ip]) {\r\n const lpKeyId = keyId as string;\r\n // Wow, what a line. Due to: https://bobbyhadz.com/blog/typescript-element-implicitly-has-any-type-expression\r\n const lpVal = this.fullys[ip][lpKeyId as keyof (typeof this.fullys)[typeof ip]];\r\n if (lpVal === value) {\r\n return this.fullys[ip];\r\n }\r\n }\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Gets Index for given keys and a value\r\n * @param config - config like CONST.cmds\r\n * @param keys - like ['mqttOn','mqttOff']\r\n * @param cmd - like 'onScreensaverStart'\r\n * @returns Index (0-...), or -1 if not found\r\n */\r\n private getIndexFromConf(config: { [k: string]: any }[], keys: string[], cmd: string): number {\r\n try {\r\n let index = -1;\r\n for (const key of keys) {\r\n // Get array index\r\n index = config.findIndex((x: { [k: string]: any }) => x[key] === cmd);\r\n if (index !== -1) break;\r\n }\r\n return index;\r\n } catch (e) {\r\n this.log.error(this.err2Str(e));\r\n return -1;\r\n }\r\n }\r\n\r\n /**\r\n * Is called when adapter shuts down - callback has to be called under any circumstances!\r\n */\r\n private onUnload(callback: () => void): void {\r\n try {\r\n if (this.fullys) {\r\n for (const ip in this.fullys) {\r\n // Set alive status to false\r\n this.setState(this.fullys[ip].id + '.alive', { val: false, ack: true });\r\n }\r\n }\r\n\r\n // Clear MQTT server timeouts\r\n if (this.mqtt_Server) {\r\n for (const clientId in this.mqtt_Server.devices) {\r\n // @ts-expect-error \"Type 'null' is not assignable to type 'Timeout'.ts(2345)\" - we check for not being null via \"if\"\r\n if (this.mqtt_Server.devices[clientId].timeoutNoUpdate) this.clearTimeout(this.mqtt_Server.devices[clientId].timeoutNoUpdate);\r\n }\r\n }\r\n\r\n // destroy MQTT Server\r\n if (this.mqtt_Server) {\r\n this.mqtt_Server.terminate();\r\n }\r\n\r\n callback();\r\n } catch (e) {\r\n callback();\r\n }\r\n }\r\n}\r\n\r\nif (require.main !== module) {\r\n // Export the constructor in compact mode\r\n module.exports = (options: Partial | undefined) => new FullyMqtt(options);\r\n} else {\r\n // otherwise start the instance directly\r\n (() => new FullyMqtt())();\r\n}\r\n"], - "mappings": "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", + "sourcesContent": ["/**\n * -------------------------------------------------------------------\n * ioBroker Fully Browser MQTT Adapter\n * @github https://github.com/Acgua/ioBroker.fully-mqtt\n * @forum https://forum.iobroker.net/topic/63705/\n * @author Acgua \n * @license Apache License 2.0\n * -------------------------------------------------------------------\n */\n\n/**\n * For all imported NPM modules, open console, change dir for example to \"C:\\iobroker\\node_modules\\ioBroker.fully-mqtt\\\"\n * and execute \"npm install \", e.g., npm install axios\n */\nimport * as utils from '@iobroker/adapter-core';\nimport { CONST } from './lib/constants';\nimport { ICmds, IDevice } from './lib/interfaces';\nimport { cleanDeviceName, err2Str, getConfigValuePerKey, isEmpty, isIpAddressValid, wait } from './lib/methods';\nimport { MqttServer } from './lib/mqtt-server';\nimport { RestApiFully } from './lib/restApi';\n\n/**\n * Main ioBroker Adapter Class\n */\nexport class FullyMqtt extends utils.Adapter {\n // Imported methods from ./lib/methods\n public err2Str = err2Str.bind(this);\n public isEmpty = isEmpty.bind(this);\n public wait = wait.bind(this);\n public cleanDeviceName = cleanDeviceName.bind(this);\n public getConfigValuePerKey = getConfigValuePerKey.bind(this);\n public isIpAddressValid = isIpAddressValid.bind(this);\n // MQTT\n private mqtt_Server: MqttServer | undefined;\n\n // REST API\n private restApi_inst = new RestApiFully(this); // RestApi Class Instance\n\n /**\n * Active Fullys: IP as key, and object per IDevice\n * {\n * '192.168.10.20': {name: 'Tablet Kitchen', id:'Tablet-Kitchen', ip:'192.168.10.20', ...},\n * '192.168.10.30': {name: 'Tablet Hallway', id:'Tablet-Hallway', ip:'192.168.10.30', ...},\n * }\n * Use this.getFullyPerKey() to get fully object per provided key\n */\n public fullys: { [ip: string]: IDevice } = {};\n\n // array of device ids, which are not activated\n public disabledDeviceIds = [] as string[];\n // All active IP addresses\n public activeDeviceIPs = [] as string[]; // for MQTT server to verify IP\n\n // Has onAliveChange() ever been called before?\n private onAliveChange_EverBeenCalledBefore = false;\n\n /**\n * Constructor\n */\n public constructor(options: Partial = {}) {\n super({ ...options, name: 'fully-mqtt' });\n\n this.on('ready', this.onReady.bind(this));\n this.on('stateChange', this.onStateChange.bind(this));\n // this.on('objectChange', this.onObjectChange.bind(this));\n // this.on('message', this.onMessage.bind(this));\n this.on('unload', this.onUnload.bind(this));\n }\n\n /**\n * Is called when databases are connected and adapter received configuration.\n */\n private async onReady(): Promise {\n try {\n /**\n * Set the connection indicator to false during startup\n */\n this.setState('info.connection', { val: false, ack: true });\n\n /**\n * Init configuration\n */\n if (await this.initConfig()) {\n this.log.debug(`Adapter settings successfully verified and initialized.`);\n } else {\n this.log.error(`Adapter settings initialization failed. ---> Please check your adapter instance settings!`);\n return;\n }\n\n /**\n * Start MQTT Server\n */\n this.mqtt_Server = new MqttServer(this);\n this.mqtt_Server.start();\n\n /**\n * Call main() for each device\n */\n for (const ip in this.fullys) {\n await this.main(this.fullys[ip]);\n }\n\n /**\n * Delete device object tree(s) if deleted or renamed in config\n */\n this.deleteRemovedDeviceObjects();\n } catch (e) {\n this.log.error(this.err2Str(e));\n return;\n }\n }\n\n /**\n * main function for each Fully Browser Device\n * @param device Fully Browser Device Object\n */\n private async main(device: IDevice): Promise {\n try {\n this.log.debug(`Start main() - ${device.name} (${device.ip})\u2026`);\n\n /**\n * Create device object(s)\n */\n // Device and Info object\n await this.setObjectNotExistsAsync(device.id, {\n type: 'device',\n common: {\n name: device.name,\n //@ts-expect-error - Object \"statusStates\" is needed for status, error is: Object literal may only specify known properties, and 'statusStates' does not exist in type 'DeviceCommon'.ts(2345)\n statusStates: { onlineId: `${this.namespace}.${device.id}.alive` },\n },\n native: {},\n });\n await this.setObjectNotExistsAsync(device.id + '.Info', { type: 'channel', common: { name: 'Device Information' }, native: {} });\n\n // Alive and info update\n await this.setObjectNotExistsAsync(device.id + '.alive', {\n type: 'state',\n common: {\n name: 'Is Fully alive?',\n desc: 'If Fully Browser is alive or not',\n type: 'boolean',\n role: 'indicator.reachable',\n icon: 'data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iTXVpU3ZnSWNvbi1yb290IE11aVN2Z0ljb24tZm9udFNpemVNZWRpdW0gaWNvbk93biBjc3MtdnViYnV2IiBmb2N1c2FibGU9ImZhbHNlIiBhcmlhLWhpZGRlbj0idHJ1ZSIgdmlld0JveD0iMCAwIDI0IDI0IiBkYXRhLXRlc3RpZD0iV2lmaUljb24iPjxwYXRoIGQ9Im0xIDkgMiAyYzQuOTctNC45NyAxMy4wMy00Ljk3IDE4IDBsMi0yQzE2LjkzIDIuOTMgNy4wOCAyLjkzIDEgOXptOCA4IDMgMyAzLTNjLTEuNjUtMS42Ni00LjM0LTEuNjYtNiAwem0tNC00IDIgMmMyLjc2LTIuNzYgNy4yNC0yLjc2IDEwIDBsMi0yQzE1LjE0IDkuMTQgOC44NyA5LjE0IDUgMTN6Ij48L3BhdGg+PC9zdmc+',\n read: true,\n write: false,\n },\n native: {},\n });\n await this.setObjectNotExistsAsync(device.id + '.lastInfoUpdate', { type: 'state', common: { name: 'Last information update', desc: 'Date/time of last information update from Fully Browser', type: 'number', role: 'value.time', read: true, write: false }, native: {} });\n\n // REST API Commands Objects\n await this.setObjectNotExistsAsync(device.id + '.Commands', { type: 'channel', common: { name: 'Commands (REST API)' }, native: {} });\n const allCommands = CONST.cmds.concat(CONST.cmdsSwitches); // join both arrays\n for (const cmdObj of allCommands) {\n let lpRole = '';\n if (cmdObj.type === 'boolean') lpRole = 'button';\n if (cmdObj.type === 'string') lpRole = 'text';\n if (cmdObj.type === 'number') lpRole = 'value';\n if (cmdObj.cmdOn && cmdObj.cmdOff) lpRole = 'switch';\n await this.setObjectNotExistsAsync(device.id + '.Commands.' + cmdObj.id, { type: 'state', common: { name: 'Command: ' + cmdObj.name, type: cmdObj.type, role: lpRole, read: true, write: true }, native: {} });\n }\n\n // Create MQTT Events Objects\n // More states are created once a new Event is received.\n await this.setObjectNotExistsAsync(device.id + '.Events', { type: 'channel', common: { name: 'MQTT Events' }, native: {} });\n for (const event of CONST.mqttEvents) {\n await this.setObjectNotExistsAsync(device.id + '.Events.' + event, { type: 'state', common: { name: 'MQTT Event: ' + event, type: 'boolean', role: 'switch', read: true, write: false }, native: {} });\n }\n\n /**\n * REST API: Subscribe to command state changes\n */\n await this.subscribeStatesAsync(device.id + '.Commands.*');\n } catch (e) {\n this.log.error(this.err2Str(e));\n return;\n }\n }\n\n /**\n * Delete device objects if device was (a) renamed or (b) deleted from devices table in adapter settings.\n * However, do not delete if it was just set inactive in table.\n */\n private async deleteRemovedDeviceObjects(): Promise {\n try {\n // Get string array of all adapter objects: ['fully-mqtt.0.info', 'fully-mqtt.0.info.connection', ...];\n const adapterObjectsIds: string[] = Object.keys(await this.getAdapterObjectsAsync());\n\n // Get all existing fully device ids of iobroker adapter objects in array: 'fully-mqtt.0.Tablet-Kitchen' -> 'Tablet-Kitchen', 'fully-mqtt.0.Tablet-Hallway' -> 'Tablet-Hallway', etc.\n const allObjectDeviceIds: Array = [];\n for (const objectId of adapterObjectsIds) {\n const deviceId = objectId.split('.')[2]; // e.g. 'Tablet-Kitchen'\n // Ignore fully-mqtt.0.info tree (which includes fully-mqtt.0.info.connection, ...). Add more to ignore as needed in the future...\n if (['info'].includes(deviceId)) {\n this.log.silly(`Cleanup: Ignore non device related state ${objectId}.`);\n } else {\n if (!allObjectDeviceIds.includes(deviceId)) allObjectDeviceIds.push(deviceId);\n }\n }\n\n // process all adapter object devices ['Tablet-Kitchen', 'Tablet-Hallway', ...] accordingly\n for (const id of allObjectDeviceIds) {\n // We handle both disabled devices and enabled devices\n const allConfigDeviceIds = this.disabledDeviceIds; // add all disabled ids first\n // now add all active ones\n for (const ip in this.fullys) {\n allConfigDeviceIds.push(this.fullys[ip].id);\n }\n\n if (!allConfigDeviceIds.includes(id)) {\n await this.delObjectAsync(id, { recursive: true });\n this.log.info(`Cleanup: Deleted no longer defined device objects of '${id}'.`);\n }\n }\n } catch (e) {\n this.log.error(this.err2Str(e));\n return;\n }\n }\n\n /**\n * Verify adapter instance settings\n */\n private async initConfig(): Promise {\n try {\n /*************************\n * MQTT Fields\n *************************/\n if (this.isEmpty(this.config.mqttPort) || this.config.mqttPort < 1 || this.config.mqttPort > 65535) {\n this.log.warn(`Adapter instance settings: MQTT Port ${this.config.mqttPort} is not allowed, set to default of 1886`);\n this.config.mqttPort = 1886;\n }\n if (this.isEmpty(this.config.mqttPublishedInfoDelay) || this.config.mqttPublishedInfoDelay < 2 || this.config.mqttPublishedInfoDelay > 120) {\n this.log.warn(`Adapter instance settings: MQTT Publish Info Delay of ${this.config.mqttPublishedInfoDelay}s is not allowed, set to default of 30s`);\n this.config.mqttPublishedInfoDelay = 30;\n }\n\n /*************************\n * REST API Fields\n *************************/\n if (this.isEmpty(this.config.restTimeout) || this.config.restTimeout < 500 || this.config.restTimeout > 15000) {\n this.log.warn(`Adapter instance settings: REST API timeout of ${this.config.restTimeout} ms is not allowed, set to default of 6000ms`);\n this.config.restTimeout = 6000;\n }\n\n /*************************\n * Table Devices\n *************************/\n if (this.isEmpty(this.config.tableDevices)) {\n this.log.error(`No Fully devices defined in adapter instance settings!`);\n return false;\n }\n const deviceIds: string[] = []; // to check for duplicate device ids\n const deviceIPs: string[] = []; // to check for duplicate device IPs\n for (let i = 0; i < this.config.tableDevices.length; i++) {\n const lpDevice = this.config.tableDevices[i];\n const finalDevice: IDevice = {\n name: '',\n id: '',\n ip: '',\n mqttInfoObjectsCreated: false,\n mqttInfoKeys: [],\n restProtocol: 'http',\n restPort: 0,\n restPassword: '',\n lastSeen: 0, // timestamp\n isAlive: false,\n };\n\n // name\n if (this.isEmpty(lpDevice.name)) {\n this.log.error(`Provided device name \"${lpDevice.name}\" is empty!`);\n return false;\n }\n finalDevice.name = lpDevice.name.trim();\n\n // id\n finalDevice.id = this.cleanDeviceName(lpDevice.name);\n if (finalDevice.id.length < 1) {\n this.log.error(`Provided device name \"${lpDevice.name}\" is too short and/or has invalid characters!`);\n return false;\n }\n if (deviceIds.includes(finalDevice.id)) {\n this.log.error(`Device \"${finalDevice.name}\" -> id:\"${finalDevice.id}\" is used for more than once device.`);\n return false;\n } else {\n deviceIds.push(finalDevice.id);\n }\n\n // REST Protocol (http/https)\n if (lpDevice.restProtocol !== 'http' && lpDevice.restProtocol !== 'https') {\n this.log.warn(`${finalDevice.name}: REST API Protocol is empty, set to http as default.`);\n finalDevice.restProtocol = 'http';\n } else {\n finalDevice.restProtocol = lpDevice.restProtocol;\n }\n\n // IP Address\n if (!this.isIpAddressValid(lpDevice.ip)) {\n this.log.error(`${finalDevice.name}: Provided IP address \"${lpDevice.ip}\" is not valid!`);\n return false;\n }\n if (deviceIPs.includes(lpDevice.ip)) {\n this.log.error(`Device \"${finalDevice.name}\" -> IP:\"${lpDevice.ip}\" is used for more than once device.`);\n return false;\n } else {\n deviceIPs.push(lpDevice.ip);\n finalDevice.ip = lpDevice.ip;\n }\n\n // REST Port\n if (isNaN(lpDevice.restPort) || lpDevice.restPort < 0 || lpDevice.restPort > 65535) {\n this.log.error(`Adapter config Fully port number ${lpDevice.restPort} is not valid, should be >= 0 and < 65536.`);\n return false;\n } else {\n finalDevice.restPort = Math.round(lpDevice.restPort);\n }\n // REST Password\n if (isEmpty(lpDevice.restPassword)) {\n this.log.error(`Remote Admin (REST API) Password must not be empty!`);\n return false;\n } else {\n finalDevice.restPassword = lpDevice.restPassword;\n }\n\n const logConfig = { ...finalDevice }; // copy object using spread\n logConfig.restPassword = '(hidden)'; // do not show password in log !\n this.log.debug(`Final Config: ${JSON.stringify(logConfig)}`);\n if (lpDevice.enabled) {\n // Finalize\n this.fullys[finalDevice.ip] = finalDevice;\n this.activeDeviceIPs.push(lpDevice.ip); // global array for all active IPs\n this.log.info(`\uD83D\uDDF8 ${finalDevice.name} (${finalDevice.ip}): Config successfully verified.`);\n } else {\n // Skip if not enabled. (but we did verification anyway!)\n this.disabledDeviceIds.push(finalDevice.id);\n this.log.debug(`Device ${finalDevice.name} (${finalDevice.ip}) is not enabled, so skip it.`);\n continue;\n }\n }\n\n if (Object.keys(this.fullys).length === 0) {\n this.log.error(`No active devices with correct configuration found.`);\n return false;\n }\n return true;\n } catch (e) {\n this.log.error(this.err2Str(e));\n return false;\n }\n }\n\n /**\n * On Alive Changes\n * for both REST API and MQTT\n */\n public async onAliveChange(source: 'MQTT' | 'REST', ip: string, isAlive: true | false, msg: string): Promise {\n try {\n const prevIsAlive = this.fullys[ip].isAlive;\n this.fullys[ip].isAlive = isAlive;\n\n // Has this function ever been called before? If adapter is restarted, we ensure log, etc.\n const calledBefore = this.onAliveChange_EverBeenCalledBefore; // Keep old value\n this.onAliveChange_EverBeenCalledBefore = true; // Now it was called\n\n /***********\n * 1 - Fully Device\n ***********/\n // if alive status changed\n if ((!calledBefore && isAlive === true) || prevIsAlive !== isAlive) {\n // Set Device isAlive Status - we could also use setStateChanged()...\n this.setState(this.fullys[ip].id + '.alive', { val: isAlive, ack: true });\n\n // log\n if (isAlive) {\n this.log.info(`${this.fullys[ip].name} is alive (${source}: ${msg})`);\n } else {\n this.log.warn(`${this.fullys[ip].name} is not alive! (${source}: ${msg})`);\n }\n } else {\n // No change\n }\n\n /***********\n * 2 - Adapter Connection indicator\n ***********/\n let countAll = 0;\n let countAlive = 0;\n for (const lpIpAddr in this.fullys) {\n countAll++;\n if (this.fullys[lpIpAddr].isAlive) {\n countAlive++;\n }\n }\n let areAllAlive = false;\n if (countAll > 0 && countAll === countAlive) areAllAlive = true;\n this.setStateChanged('info.connection', { val: areAllAlive, ack: true });\n } catch (e) {\n this.log.error(this.err2Str(e));\n return;\n }\n }\n\n /**\n * MQTT: once new device info packet is coming in\n */\n public async onMqttInfo(obj: { clientId: string; ip: string; topic: string; infoObj: { [k: string]: any } }): Promise {\n try {\n // log\n this.log.debug(`[MQTT]\uD83D\uDCE1 ${this.fullys[obj.ip].name} published info, topic: ${obj.topic}`);\n //this.log.debug(`[MQTT] Client ${obj.ip} Publish Info: Details: ${JSON.stringify(obj.infoObj)}`);\n\n // Create info objects if not yet existing\n const formerInfoKeysLength: number = this.fullys[obj.ip].mqttInfoKeys.length;\n const newInfoKeysAdded: string[] = [];\n for (const key in obj.infoObj) {\n const val = obj.infoObj[key];\n const valType = typeof val;\n // only accept certain types\n if (valType !== 'string' && valType !== 'boolean' && valType !== 'object' && valType !== 'number') {\n this.log.warn(`[MQTT] ${this.fullys[obj.ip].name}: Unknown type ${valType} of key '${key}' in info object`);\n continue;\n }\n // Create info object if not yet seen - this check is used for increasing performance by not unnesserily call setObjectNotExistsAsync() every time new info package comes in\n if (!this.fullys[obj.ip].mqttInfoKeys.includes(key)) {\n this.fullys[obj.ip].mqttInfoKeys.push(key);\n newInfoKeysAdded.push(key);\n await this.setObjectNotExistsAsync(`${this.fullys[obj.ip].id}.Info.${key}`, { type: 'state', common: { name: 'Info: ' + key, type: valType, role: 'value', read: true, write: false }, native: {} });\n }\n }\n if (formerInfoKeysLength === 0) this.log.debug(`[MQTT] ${this.fullys[obj.ip].name}: Initially create states for ${newInfoKeysAdded.length} info items (if not yet existing)`);\n if (formerInfoKeysLength > 0 && newInfoKeysAdded.length > 0) this.log.info(`[MQTT] ${this.fullys[obj.ip].name}: Created new info object(s) as not seen before (if object(s) did not exist): ${newInfoKeysAdded.join(', ')}`);\n\n // Set info objects\n for (const key in obj.infoObj) {\n const newVal = typeof obj.infoObj[key] === 'object' ? JSON.stringify(obj.infoObj[key]) : obj.infoObj[key]; // https://forum.iobroker.net/post/628870 - https://forum.iobroker.net/post/960260\n if (this.config.mqttUpdateUnchangedObjects) {\n this.setState(`${this.fullys[obj.ip].id}.Info.${key}`, { val: newVal, ack: true });\n } else {\n this.setStateChanged(`${this.fullys[obj.ip].id}.Info.${key}`, { val: newVal, ack: true });\n }\n }\n this.setState(this.fullys[obj.ip].id + '.lastInfoUpdate', { val: Date.now(), ack: true });\n this.setState(this.fullys[obj.ip].id + '.alive', { val: true, ack: true });\n } catch (e) {\n this.log.error(this.err2Str(e));\n return;\n }\n }\n\n /**\n * MQTT: once new event packet is coming in\n */\n public async onMqttEvent(obj: { clientId: string; ip: string; topic: string; cmd: string }): Promise {\n try {\n // log\n this.log.debug(`[MQTT] \uD83D\uDCE1 ${this.fullys[obj.ip].name} published event, topic: ${obj.topic}, cmd: ${obj.cmd}`);\n\n /**\n * Set Event State\n */\n const pthEvent = `${this.fullys[obj.ip].id}.Events.${obj.cmd}`;\n if (!(await this.getObjectAsync(pthEvent))) {\n this.log.info(`[MQTT] ${this.fullys[obj.ip].name}: Event ${obj.cmd} received but state ${pthEvent} does not exist, so we create it first`);\n await this.setObjectNotExistsAsync(pthEvent, { type: 'state', common: { name: 'MQTT Event: ' + obj.cmd, type: 'boolean', role: 'switch', read: true, write: false }, native: {} });\n }\n this.setState(pthEvent, { val: true, ack: true });\n\n /**\n * Confirm Command state(s) with ack: true\n */\n const pthCmd = this.fullys[obj.ip].id + '.Commands';\n\n // Check if it is a switch with MQTT commands connected\n const idx = this.getIndexFromConf(CONST.cmdsSwitches, ['mqttOn', 'mqttOff'], obj.cmd);\n if (idx !== -1) {\n // We have a switch\n const conf = CONST.cmdsSwitches[idx]; // the found line from config array\n const onOrOffCmd = obj.cmd === conf.mqttOn ? true : false;\n await this.setStateAsync(`${pthCmd}.${conf.id}`, { val: onOrOffCmd, ack: true });\n await this.setStateAsync(`${pthCmd}.${conf.cmdOn}`, { val: onOrOffCmd, ack: true });\n await this.setStateAsync(`${pthCmd}.${conf.cmdOff}`, { val: !onOrOffCmd, ack: true });\n } else {\n // No switch\n const idx = this.getIndexFromConf(CONST.cmds, ['id'], obj.cmd);\n if (idx !== -1 && CONST.cmds[idx].type === 'boolean') {\n // We have a button, so set it to true\n await this.setStateAsync(`${pthCmd}.${obj.cmd}`, { val: true, ack: true });\n } else {\n this.log.silly(`[MQTT] ${this.fullys[obj.ip].name}: Event cmd ${obj.cmd} - no REST API command is existing, so skip confirmation with with ack:true`);\n }\n }\n } catch (e) {\n this.log.error(this.err2Str(e));\n return;\n }\n }\n\n /**\n * Called once a subscribed state changes.\n * Ready once subscribeStatesAsync() is called...\n * @param id - e.g. \"fully-mqtt.0.Tablet-Bathroom.Commands.screenSwitch\"\n * @param stateObj - e.g. { val: true, ack: false, ts: 123456789, q: 0, lc: 123456789 }\n */\n private async onStateChange(stateId: string, stateObj: ioBroker.State | null | undefined): Promise {\n try {\n if (!stateObj) return; // state was deleted, we disregard...\n if (stateObj.ack) return; // ignore ack:true\n const idSplit = stateId.split('.');\n const deviceId = idSplit[2]; // \"Tablet-Bathroom\"\n const channel = idSplit[3]; // \"Commands\"\n const cmd = idSplit[4]; // \"screenSwitch\"\n const pth = deviceId + '.' + channel; // Tablet-Bathroom.Commands\n /**\n * Commands\n */\n if (channel === 'Commands') {\n this.log.debug(`state ${stateId} changed: ${stateObj.val} (ack = ${stateObj.ack})`);\n // Get device object\n const fully = this.getFullyByKey('id', deviceId);\n if (!fully) throw `Fully object for deviceId '${deviceId}' not found!`;\n\n let cmdToSend: string | undefined = cmd; // Command to send to Fully\n let switchConf: undefined | ICmds = undefined; // Config line of switch\n\n /****************\n * Check if it is a switch state cmd, like 'screenSwitch'\n ****************/\n const idxSw = this.getIndexFromConf(CONST.cmdsSwitches, ['id'], cmd);\n if (idxSw !== -1) {\n // It is a switch\n switchConf = CONST.cmdsSwitches[idxSw]; // the found line from config array\n cmdToSend = stateObj.val ? switchConf.cmdOn : switchConf.cmdOff;\n } else {\n // Not a switch.\n // If val is false, we disregard, since it is a button only\n if (!stateObj.val) return;\n }\n if (!cmdToSend) throw `onStateChange() - ${stateId}: fullyCmd could not be determined!`;\n\n /**\n * Send Command\n */\n const sendCommand = await this.restApi_inst.sendCmd(fully, cmdToSend, stateObj.val);\n if (sendCommand) {\n this.log.info(`${fully.name}: ${cmd} successfully set to ${stateObj.val}`);\n /**\n * Confirm with ack:true\n */\n if (switchConf !== undefined) {\n // it is a switch\n const onOrOffCmdVal = cmd === switchConf.cmdOn ? true : false;\n await this.setStateAsync(`${pth}.${switchConf.id}`, { val: onOrOffCmdVal, ack: true });\n await this.setStateAsync(`${pth}.${switchConf.cmdOn}`, { val: onOrOffCmdVal, ack: true });\n await this.setStateAsync(`${pth}.${switchConf.cmdOff}`, { val: !onOrOffCmdVal, ack: true });\n } else {\n // No switch\n if (typeof stateObj.val === 'boolean') {\n const idx = this.getIndexFromConf(CONST.cmds, ['id'], cmd);\n if (idx !== -1) {\n if (CONST.cmds[idx].type === 'boolean') {\n // Is a button\n await this.setStateAsync(stateId, { val: true, ack: true });\n } else {\n // This should actually not happen, as we just define buttons in commands, but anyway\n this.log.warn(`${fully.name}: ${stateId} - val: ${stateObj.val} is boolean, but cmd ${cmd} is not defined in CONF`);\n await this.setStateAsync(stateId, { val: stateObj.val, ack: true });\n }\n } else {\n this.log.warn(`${fully.name}: ${stateId} - val: ${stateObj.val}, cmd ${cmd} is not defined in CONF`);\n }\n } else {\n // Non-boolean, so just set val with ack:true...\n await this.setStateAsync(stateId, { val: stateObj.val, ack: true });\n }\n }\n } else {\n // log, more log lines were already published by this.restApi_inst.sendCmd()\n this.log.debug(`${fully.name}: restApiSendCmd() was not successful (${stateId})`);\n }\n }\n } catch (e) {\n this.log.error(this.err2Str(e));\n return;\n }\n }\n\n /**\n * Get Fully Object per provided key and value\n * {\n * '192.168.10.20': {name: 'Tablet Kitchen', id:'Tablet-Kitchen', ip:'192.168.10.20', ...},\n * '192.168.10.30': {name: 'Tablet Hallway', id:'Tablet-Hallway', ip:'192.168.10.30', ...},\n * }\n * getFullyByKey('id', 'Tablet-Hallway') will return the second object...\n * @param keyId - e.g. 'id', 'name', ...\n * @param value - e.g. 'Tablet Hallway', ...\n * @returns - fully object or false if not found\n */\n private getFullyByKey(keyId: string, value: any): IDevice | false {\n for (const ip in this.fullys) {\n if (keyId in this.fullys[ip]) {\n const lpKeyId = keyId as string;\n // Wow, what a line. Due to: https://bobbyhadz.com/blog/typescript-element-implicitly-has-any-type-expression\n const lpVal = this.fullys[ip][lpKeyId as keyof (typeof this.fullys)[typeof ip]];\n if (lpVal === value) {\n return this.fullys[ip];\n }\n }\n }\n return false;\n }\n\n /**\n * Gets Index for given keys and a value\n * @param config - config like CONST.cmds\n * @param keys - like ['mqttOn','mqttOff']\n * @param cmd - like 'onScreensaverStart'\n * @returns Index (0-...), or -1 if not found\n */\n private getIndexFromConf(config: { [k: string]: any }[], keys: string[], cmd: string): number {\n try {\n let index = -1;\n for (const key of keys) {\n // Get array index\n index = config.findIndex((x: { [k: string]: any }) => x[key] === cmd);\n if (index !== -1) break;\n }\n return index;\n } catch (e) {\n this.log.error(this.err2Str(e));\n return -1;\n }\n }\n\n /**\n * Is called when adapter shuts down - callback has to be called under any circumstances!\n */\n private onUnload(callback: () => void): void {\n try {\n if (this.fullys) {\n for (const ip in this.fullys) {\n // Set alive status to false\n this.setState(this.fullys[ip].id + '.alive', { val: false, ack: true });\n }\n }\n\n // Clear MQTT server timeouts\n if (this.mqtt_Server) {\n for (const clientId in this.mqtt_Server.devices) {\n // @ts-expect-error \"Type 'null' is not assignable to type 'Timeout'.ts(2345)\" - we check for not being null via \"if\"\n if (this.mqtt_Server.devices[clientId].timeoutNoUpdate) this.clearTimeout(this.mqtt_Server.devices[clientId].timeoutNoUpdate);\n }\n }\n\n // destroy MQTT Server\n if (this.mqtt_Server) {\n this.mqtt_Server.terminate();\n }\n\n callback();\n } catch (e) {\n callback();\n }\n }\n}\n\nif (require.main !== module) {\n // Export the constructor in compact mode\n module.exports = (options: Partial | undefined) => new FullyMqtt(options);\n} else {\n // otherwise start the instance directly\n (() => new FullyMqtt())();\n}\n"], + "mappings": "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", "names": ["idx"] } diff --git a/src/main.ts b/src/main.ts index 0201852..ecba1c6 100644 --- a/src/main.ts +++ b/src/main.ts @@ -32,7 +32,6 @@ export class FullyMqtt extends utils.Adapter { public isIpAddressValid = isIpAddressValid.bind(this); // MQTT private mqtt_Server: MqttServer | undefined; - public mqtt_useMqtt: true | false = false; // Is use of MQTT activated per adapter settings (each line of fully devices is checked) // REST API private restApi_inst = new RestApiFully(this); // RestApi Class Instance @@ -91,10 +90,8 @@ export class FullyMqtt extends utils.Adapter { /** * Start MQTT Server */ - if (this.mqtt_useMqtt) { - this.mqtt_Server = new MqttServer(this); - this.mqtt_Server.start(); - } + this.mqtt_Server = new MqttServer(this); + this.mqtt_Server.start(); /** * Call main() for each device @@ -331,16 +328,7 @@ export class FullyMqtt extends utils.Adapter { logConfig.restPassword = '(hidden)'; // do not show password in log ! this.log.debug(`Final Config: ${JSON.stringify(logConfig)}`); if (lpDevice.enabled) { - // if MQTT is activated, set variable to true - if (lpDevice.useMQTT) { - this.mqtt_useMqtt = true; - this.log.info(`${finalDevice.name} (${finalDevice.ip}) MQTT is activated in adapter instance settings.`); - } else { - this.log.info(`${finalDevice.name} (${finalDevice.ip}) MQTT is not activated in adapter instance settings.`); - } - // Finalize - this.fullys[finalDevice.ip] = finalDevice; this.activeDeviceIPs.push(lpDevice.ip); // global array for all active IPs this.log.info(`🗸 ${finalDevice.name} (${finalDevice.ip}): Config successfully verified.`);