diff --git a/LICENSE b/LICENSE index 43659c4..b8eb972 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 sestriel +Copyright (c) 2023-2024 sestriel Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index af17336..3c83394 100644 --- a/README.md +++ b/README.md @@ -1,108 +1,39 @@ ![Logo](admin/ntfy.png) -# ioBroker.ntfy +# ioBroker ntfy.sh adapter -[![NPM version](https://img.shields.io/npm/v/iobroker.ntfy.svg)](https://www.npmjs.com/package/iobroker.ntfy) -[![Downloads](https://img.shields.io/npm/dm/iobroker.ntfy.svg)](https://www.npmjs.com/package/iobroker.ntfy) -![Number of Installations](https://iobroker.live/badges/ntfy-installed.svg) -![Current version in stable repository](https://iobroker.live/badges/ntfy-stable.svg) +[![NPM version](https://img.shields.io/npm/v/iobroker.ntfy.svg)](https://www.npmjs.com/package/iobroker.ntfy) [![Downloads](https://img.shields.io/npm/dm/iobroker.ntfy.svg)](https://www.npmjs.com/package/iobroker.ntfy) ![Number of Installations](https://iobroker.live/badges/ntfy-installed.svg) ![Current version in stable repository](https://iobroker.live/badges/ntfy-stable.svg) +![Test and Release](https://github.com/sestriel/ioBroker.ntfy/workflows/Test%20and%20Release/badge.svg) -[![NPM](https://nodei.co/npm/iobroker.ntfy.png?downloads=true)](https://nodei.co/npm/iobroker.ntfy/) +Use your ntfy.sh (free selfhosted) server to send and receive push notifications -**Tests:** ![Test and Release](https://github.com/sestriel/ioBroker.ntfy/workflows/Test%20and%20Release/badge.svg) +* Integrates an Blockly to easily send notifications + - Currently supported: Title, Message, Priority +* Subscribe to topics without the need of extra javascript/blockly + - messages will be pushed to the corresponding, auto-created ioBroker object +* Send and receive from as many topics as you want -## ntfy adapter for ioBroker - -Use your ntfy.sh (free selfhosted) server for Push Notifications - -## Developer manual -This section is intended for the developer. It can be deleted later. - -### DISCLAIMER - -Please make sure that you consider copyrights and trademarks when you use names or logos of a company and add a disclaimer to your README. -You can check other adapters for examples or ask in the developer community. Using a name or logo of a company without permission may cause legal problems for you. - -### Getting started - -You are almost done, only a few steps left: -1. Create a new repository on GitHub with the name `ioBroker.ntfy` - -1. Push all files to the GitHub repo. The creator has already set up the local repository for you: - ```bash - git push origin main - ``` -1. Add a new secret under https://github.com/sestriel/ioBroker.ntfy/settings/secrets. It must be named `AUTO_MERGE_TOKEN` and contain a personal access token with push access to the repository, e.g. yours. You can create a new token under https://github.com/settings/tokens. - -1. Head over to [main.js](main.js) and start programming! - -### Best Practices -We've collected some [best practices](https://github.com/ioBroker/ioBroker.repositories#development-and-coding-best-practices) regarding ioBroker development and coding in general. If you're new to ioBroker or Node.js, you should -check them out. If you're already experienced, you should also take a look at them - you might learn something new :) - -### Scripts in `package.json` -Several npm scripts are predefined for your convenience. You can run them using `npm run ` -| Script name | Description | -|-------------|-------------| -| `test:js` | Executes the tests you defined in `*.test.js` files. | -| `test:package` | Ensures your `package.json` and `io-package.json` are valid. | -| `test:integration` | Tests the adapter startup with an actual instance of ioBroker. | -| `test` | Performs a minimal test run on package files and your tests. | -| `check` | Performs a type-check on your code (without compiling anything). | -| `lint` | Runs `ESLint` to check your code for formatting errors and potential bugs. | -| `translate` | Translates texts in your adapter to all required languages, see [`@iobroker/adapter-dev`](https://github.com/ioBroker/adapter-dev#manage-translations) for more details. | -| `release` | Creates a new release, see [`@alcalzone/release-script`](https://github.com/AlCalzone/release-script#usage) for more details. | - -### Writing tests -When done right, testing code is invaluable, because it gives you the -confidence to change your code while knowing exactly if and when -something breaks. A good read on the topic of test-driven development -is https://hackernoon.com/introduction-to-test-driven-development-tdd-61a13bc92d92. -Although writing tests before the code might seem strange at first, but it has very -clear upsides. - -The template provides you with basic tests for the adapter startup and package files. -It is recommended that you add your own tests into the mix. - -### Publishing the adapter -Using GitHub Actions, you can enable automatic releases on npm whenever you push a new git tag that matches the form -`v..`. We **strongly recommend** that you do. The necessary steps are described in `.github/workflows/test-and-release.yml`. - -Since you installed the release script, you can create a new -release simply by calling: -```bash -npm run release -``` -Additional command line options for the release script are explained in the -[release-script documentation](https://github.com/AlCalzone/release-script#command-line). - -To get your adapter released in ioBroker, please refer to the documentation -of [ioBroker.repositories](https://github.com/ioBroker/ioBroker.repositories#requirements-for-adapter-to-get-added-to-the-latest-repository). - -### Test the adapter manually with dev-server -Since you set up `dev-server`, you can use it to run, test and debug your adapter. - -You may start `dev-server` by calling from your dev directory: -```bash -dev-server watch -``` - -The ioBroker.admin interface will then be available at http://localhost:8081/ - -Please refer to the [`dev-server` documentation](https://github.com/ioBroker/dev-server#command-line) for more details. +### Known bugs and errors +* ntfy has an invalid jsonConfig (see [Issue](https://github.com/ioBroker/adapter-react-v5/issues/292)) ## Changelog - - -### **WORK IN PROGRESS** -* (sestriel) initial release +### 0.2.1 (2024-04-12) +* (sestriel) Added proper unload handler +* (sestriel) Fixed some errors shown from adapter-checker +* (sestriel) Updated Readme +### 0.2.0 (2024-04-12) +* (sestriel) Added ability to subscribe to topics +### 0.1.2 (2023-10-05) +* (sestriel) Added presets for more topics +* (sestriel) Added proper authorization for default topic +### 0.1.1 (2023-09-28) +* (sestriel) First working release +### 0.1.0 (2023-09-27) +* (sestriel) Initial release ## License MIT License -Copyright (c) 2023 sestriel +Copyright (c) 2023-2024 sestriel Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md.bk b/README.md.bk new file mode 100644 index 0000000..1e4ecd6 --- /dev/null +++ b/README.md.bk @@ -0,0 +1,123 @@ +![Logo](admin/ntfy.png) +# ioBroker.ntfy + +[![NPM version](https://img.shields.io/npm/v/iobroker.ntfy.svg)](https://www.npmjs.com/package/iobroker.ntfy) +[![Downloads](https://img.shields.io/npm/dm/iobroker.ntfy.svg)](https://www.npmjs.com/package/iobroker.ntfy) +![Number of Installations](https://iobroker.live/badges/ntfy-installed.svg) +![Current version in stable repository](https://iobroker.live/badges/ntfy-stable.svg) + +[![NPM](https://nodei.co/npm/iobroker.ntfy.png?downloads=true)](https://nodei.co/npm/iobroker.ntfy/) + +**Tests:** ![Test and Release](https://github.com/sestriel/ioBroker.ntfy/workflows/Test%20and%20Release/badge.svg) + +## ntfy adapter for ioBroker + +Use your ntfy.sh (free selfhosted) server for Push Notifications + +## Developer manual +This section is intended for the developer. It can be deleted later. + +### DISCLAIMER + +Please make sure that you consider copyrights and trademarks when you use names or logos of a company and add a disclaimer to your README. +You can check other adapters for examples or ask in the developer community. Using a name or logo of a company without permission may cause legal problems for you. + +### Getting started + +You are almost done, only a few steps left: +1. Create a new repository on GitHub with the name `ioBroker.ntfy` + +1. Push all files to the GitHub repo. The creator has already set up the local repository for you: + ```bash + git push origin main + ``` +1. Add a new secret under https://github.com/sestriel/ioBroker.ntfy/settings/secrets. It must be named `AUTO_MERGE_TOKEN` and contain a personal access token with push access to the repository, e.g. yours. You can create a new token under https://github.com/settings/tokens. + +1. Head over to [main.js](main.js) and start programming! + +### Best Practices +We've collected some [best practices](https://github.com/ioBroker/ioBroker.repositories#development-and-coding-best-practices) regarding ioBroker development and coding in general. If you're new to ioBroker or Node.js, you should +check them out. If you're already experienced, you should also take a look at them - you might learn something new :) + +### Scripts in `package.json` +Several npm scripts are predefined for your convenience. You can run them using `npm run ` +| Script name | Description | +|-------------|-------------| +| `test:js` | Executes the tests you defined in `*.test.js` files. | +| `test:package` | Ensures your `package.json` and `io-package.json` are valid. | +| `test:integration` | Tests the adapter startup with an actual instance of ioBroker. | +| `test` | Performs a minimal test run on package files and your tests. | +| `check` | Performs a type-check on your code (without compiling anything). | +| `lint` | Runs `ESLint` to check your code for formatting errors and potential bugs. | +| `translate` | Translates texts in your adapter to all required languages, see [`@iobroker/adapter-dev`](https://github.com/ioBroker/adapter-dev#manage-translations) for more details. | +| `release` | Creates a new release, see [`@alcalzone/release-script`](https://github.com/AlCalzone/release-script#usage) for more details. | + +### Writing tests +When done right, testing code is invaluable, because it gives you the +confidence to change your code while knowing exactly if and when +something breaks. A good read on the topic of test-driven development +is https://hackernoon.com/introduction-to-test-driven-development-tdd-61a13bc92d92. +Although writing tests before the code might seem strange at first, but it has very +clear upsides. + +The template provides you with basic tests for the adapter startup and package files. +It is recommended that you add your own tests into the mix. + +### Publishing the adapter +Using GitHub Actions, you can enable automatic releases on npm whenever you push a new git tag that matches the form +`v..`. We **strongly recommend** that you do. The necessary steps are described in `.github/workflows/test-and-release.yml`. + +Since you installed the release script, you can create a new +release simply by calling: +```bash +npm run release +``` +Additional command line options for the release script are explained in the +[release-script documentation](https://github.com/AlCalzone/release-script#command-line). + +To get your adapter released in ioBroker, please refer to the documentation +of [ioBroker.repositories](https://github.com/ioBroker/ioBroker.repositories#requirements-for-adapter-to-get-added-to-the-latest-repository). + +### Test the adapter manually with dev-server +Since you set up `dev-server`, you can use it to run, test and debug your adapter. + +You may start `dev-server` by calling from your dev directory: +```bash +dev-server watch +``` + +The ioBroker.admin interface will then be available at http://localhost:8081/ + +Please refer to the [`dev-server` documentation](https://github.com/ioBroker/dev-server#command-line) for more details. + +## Changelog + + +### **WORK IN PROGRESS** +* (sestriel) initial release + +## License +MIT License + +Copyright (c) 2023-2024 sestriel + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/main.js b/main.js index 3d4bdd0..7ceadbd 100644 --- a/main.js +++ b/main.js @@ -1,8 +1,8 @@ -'use strict' +'use strict'; -const utils = require('@iobroker/adapter-core') -const axios = require('axios') -const EventSource = require('eventsource') +const utils = require('@iobroker/adapter-core'); +const axios = require('axios'); +const EventSource = require('eventsource'); class ntfy extends utils.Adapter { @@ -14,31 +14,52 @@ class ntfy extends utils.Adapter { super({ ...options, name: 'ntfy', - }) + }); - this.messageTime = 0 - this.messageText = '' - this.topicSubscriptionData = {} - this.checkSubscriptionsTimeout = null + this.messageTime = 0; + this.messageText = ''; + this.topicSubscriptionData = {}; + this.checkSubscriptionsTimeout = null; - this.on('ready', this.onReady.bind(this)) - this.on('message', this.onMessage.bind(this)) + this.on('ready', this.onReady.bind(this)); + this.on('message', this.onMessage.bind(this)); + this.on('unload', this.onUnload.bind(this)); } async onReady() { - this.setState('info.connection', false, true) + this.setState('info.connection', false, true); if (!await this.checkConfig()) { - this.checkTopic() - this.checkAuth() - return + this.checkTopic(); + this.checkAuth(); + return; } - this.setState('info.connection', true, true) - - await this.subscribeTopics() + this.setState('info.connection', true, true); - this.startCheckSubscriptions() + await this.subscribeTopics(); + + this.startCheckSubscriptions(); + } + + onUnload(callback) + { + try { + if (this.checkSubscriptionsTimeout) { + clearTimeout(this.checkSubscriptionsTimeout); + } + + for (const topicName of Object.entries(this.topicSubscriptionData)) { + if (this.topicSubscriptionData[topicName].eventSource === null) continue; + this.topicSubscriptionData[topicName].eventSource.close(); + this.setState(this.topicSubscriptionData[topicName].topicKey + '.connected', {ack: true, val: false}); + this.setState('info.connection', true, false); + } + + callback(); + } catch (e) { + callback(); + } } /** @@ -48,26 +69,26 @@ class ntfy extends utils.Adapter { { if (typeof obj === 'object' && obj.message) { if (obj.message === 'checkSubscriptions') { - this.startCheckSubscriptions() - return + this.startCheckSubscriptions(); + return; } if (obj.command === 'send') { if (await this.checkConfig()) { - this.sendMessage(obj) + this.sendMessage(obj); } } - + } - + if (typeof obj === 'object' && obj.command) { if (obj.command === 'testBtn') { - let testMsg + let testMsg; if (typeof this.config.presetTopics !== 'object' || this.config.presetTopics.length <= 0) { - testMsg = 'Presets: None' + testMsg = 'Presets: None'; } else { - testMsg = `Presets: ${JSON.stringify(this.config.presetTopics)}` + testMsg = `Presets: ${JSON.stringify(this.config.presetTopics)}`; } - this.sendTo(obj.from, obj.command, { result: testMsg }, obj.callback) + this.sendTo(obj.from, obj.command, { result: testMsg }, obj.callback); } } } @@ -76,83 +97,83 @@ class ntfy extends utils.Adapter { async checkConfig() { if (!this.config.serverURL) { - this.log.error('Ntfy-Config: Server-URL is not set') - return false + this.log.error('Ntfy-Config: Server-URL is not set'); + return false; } try { - const response = await axios.get(this.config.serverURL) + const response = await axios.get(this.config.serverURL); if (response.status !== 200) { - this.log.error('Ntfy-Config: Server-URL is not reachable') - return false + this.log.error('Ntfy-Config: Server-URL is not reachable'); + return false; } } catch(err) { - this.log.error('Ntfy-Config: Server-URL is not reachable') - return false + this.log.error('Ntfy-Config: Server-URL is not reachable'); + return false; } - return true + return true; } checkTopic() { if (!this.config.defaultTopic) { - this.log.info('Ntfy-Config: No default topic is set') - return false + this.log.info('Ntfy-Config: No default topic is set'); + return false; } - return true + return true; } checkAuth() { - if ( this.config.defaultTopicAuth !== 0 && - ( this.config.defaultTopicAuth === 1 && ( !this.config.defaultUsername && !this.config.defaultPassword ) ) || + if ( this.config.defaultTopicAuth !== 0 && + ( this.config.defaultTopicAuth === 1 && ( !this.config.defaultUsername && !this.config.defaultPassword ) ) || ( this.config.defaultTopicAuth === 2 && !this.config.defaultAccessToken ) ) { - this.log.info('Ntfy-Config: No default credentials are set (either username & password or access token)') - return false + this.log.info('Ntfy-Config: No default credentials are set (either username & password or access token)'); + return false; } - return true + return true; } sendMessage(obj) { - if (!obj.message.topic) obj.message.topic = this.config.defaultTopic + if (!obj.message.topic) obj.message.topic = this.config.defaultTopic; - const json = JSON.stringify(obj.message) + const json = JSON.stringify(obj.message); if (this.messageTime && this.messageText === json && Date.now() - this.messageTime < 1000) { - return + return; } - this.messageTime = Date.now() - this.messageText = json + this.messageTime = Date.now(); + this.messageText = json; - let axiosConfig = {} + let axiosConfig = {}; if (this.config.defaultTopicAuth === 1) { - axiosConfig = { headers: { 'Authorization': 'Basic ' + Buffer.from(this.config.defaultUsername + ':' + this.config.defaultPassword).toString('base64') } } + axiosConfig = { headers: { 'Authorization': 'Basic ' + Buffer.from(this.config.defaultUsername + ':' + this.config.defaultPassword).toString('base64') } }; } else if (this.config.defaultTopicAuth === 2) { - axiosConfig = { headers: { 'Authorization': 'Bearer ' + this.config.defaultAccessToken } } + axiosConfig = { headers: { 'Authorization': 'Bearer ' + this.config.defaultAccessToken } }; } axios.post(this.config.serverURL, json, axiosConfig) .catch(err => { - this.log.error(`Ntfy error: ${err}`) - this.log.error(`Ntfy error: ${JSON.stringify(err.response.data)}`) - this.log.error(`Ntfy with config: ${JSON.stringify(axiosConfig)}`) - }) + this.log.error(`Ntfy error: ${err}`); + this.log.error(`Ntfy error: ${JSON.stringify(err.response.data)}`); + this.log.error(`Ntfy with config: ${JSON.stringify(axiosConfig)}`); + }); } async subscribeTopics() { if (this.config.defaultSubscribed) { - await this.subscribeTopic(this.config.defaultTopic, this.config.defaultTopicAuth, this.config.defaultUsername, this.config.defaultPassword, this.config.defaultAccessToken) + await this.subscribeTopic(this.config.defaultTopic, this.config.defaultTopicAuth, this.config.defaultUsername, this.config.defaultPassword, this.config.defaultAccessToken); } - + if (typeof this.config.presetTopics === 'object' || this.config.presetTopics.length > 0) { this.config.presetTopics.forEach( async (presetTopic) => { if (presetTopic.presetTopicSubscribed) { - await this.subscribeTopic(presetTopic.presetTopicName, presetTopic.presetTopicAuth, presetTopic.presetTopicUsername, presetTopic.presetTopicPassword, presetTopic.presetTopicAccessToken) + await this.subscribeTopic(presetTopic.presetTopicName, presetTopic.presetTopicAuth, presetTopic.presetTopicUsername, presetTopic.presetTopicPassword, presetTopic.presetTopicAccessToken); } - }) + }); } } @@ -169,89 +190,89 @@ class ntfy extends utils.Adapter { messageKey: 'subscribedTopics.' + topicName + '.lastMessage.', connected: false, eventSource : null - } + }; if (this.topicSubscriptionData[topicName].eventSource !== null && this.topicSubscriptionData[topicName].eventSource.readyState !== 2) { - return + return; } - - await this.createSubsrciptionObjects(topicName) - let subscribtionEventSourceConfig = {} + await this.createSubsrciptionObjects(topicName); + + let subscribtionEventSourceConfig = {}; switch(authType) { case 1: - subscribtionEventSourceConfig = { headers: { 'Authorization': 'Basic ' + Buffer.from(username + ':' + password).toString('base64') } } - break + subscribtionEventSourceConfig = { headers: { 'Authorization': 'Basic ' + Buffer.from(username + ':' + password).toString('base64') } }; + break; case 2: - subscribtionEventSourceConfig = { headers: { 'Authorization': 'Bearer ' + accessToken } } - break + subscribtionEventSourceConfig = { headers: { 'Authorization': 'Bearer ' + accessToken } }; + break; } - this.topicSubscriptionData[topicName].eventSource = new EventSource(this.config.serverURL + '/' + topicName + '/sse', subscribtionEventSourceConfig) + this.topicSubscriptionData[topicName].eventSource = new EventSource(this.config.serverURL + '/' + topicName + '/sse', subscribtionEventSourceConfig); this.topicSubscriptionData[topicName].eventSource.onmessage = (e) => { - this.log.debug('Received new message from topic ' + topicName) - - const msgData = JSON.parse(e.data) - - this.setState(this.topicSubscriptionData[topicName].topicKey + '.lastMessageRaw', {ack: true, val: e.data}) - this.setState(this.topicSubscriptionData[topicName].messageKey + 'id', {ack: true, val: msgData.id}) - this.setState(this.topicSubscriptionData[topicName].messageKey + 'time', {ack: true, val: msgData.time}) - this.setState(this.topicSubscriptionData[topicName].messageKey + 'tags', {ack: true, val: msgData.tags}) - this.setState(this.topicSubscriptionData[topicName].messageKey + 'event', {ack: true, val: msgData.event}) - this.setState(this.topicSubscriptionData[topicName].messageKey + 'title', {ack: true, val: msgData.title}) - this.setState(this.topicSubscriptionData[topicName].messageKey + 'value', {ack: true, val: msgData.message}) - this.setState(this.topicSubscriptionData[topicName].messageKey + 'expires', {ack: true, val: msgData.expires}) - this.setState(this.topicSubscriptionData[topicName].messageKey + 'priority', {ack: true, val: msgData.priority}) - } + this.log.debug('Received new message from topic ' + topicName); + + const msgData = JSON.parse(e.data); + + this.setState(this.topicSubscriptionData[topicName].topicKey + '.lastMessageRaw', {ack: true, val: e.data}); + this.setState(this.topicSubscriptionData[topicName].messageKey + 'id', {ack: true, val: msgData.id}); + this.setState(this.topicSubscriptionData[topicName].messageKey + 'time', {ack: true, val: msgData.time}); + this.setState(this.topicSubscriptionData[topicName].messageKey + 'tags', {ack: true, val: msgData.tags}); + this.setState(this.topicSubscriptionData[topicName].messageKey + 'event', {ack: true, val: msgData.event}); + this.setState(this.topicSubscriptionData[topicName].messageKey + 'title', {ack: true, val: msgData.title}); + this.setState(this.topicSubscriptionData[topicName].messageKey + 'value', {ack: true, val: msgData.message}); + this.setState(this.topicSubscriptionData[topicName].messageKey + 'expires', {ack: true, val: msgData.expires}); + this.setState(this.topicSubscriptionData[topicName].messageKey + 'priority', {ack: true, val: msgData.priority}); + }; this.topicSubscriptionData[topicName].eventSource.onopen = () => { if (!this.topicSubscriptionData[topicName].connected) { - this.log.debug('Subscription to topic ' + topicName + ' established.') - this.setState(this.topicSubscriptionData[topicName].topicKey + '.connected', {ack: true, val: true}) - this.topicSubscriptionData[topicName].connected = true + this.log.debug('Subscription to topic ' + topicName + ' established.'); + this.setState(this.topicSubscriptionData[topicName].topicKey + '.connected', {ack: true, val: true}); + this.topicSubscriptionData[topicName].connected = true; } - } + }; this.topicSubscriptionData[topicName].eventSource.onerror = (e) => { - this.log.error('Subscription to topic ' + topicName + ' cant be established or lost. Status code: ' + e.status + ' Error: ' + e.message) - this.setState(this.topicSubscriptionData[topicName].topicKey + '.connected', {ack: true, val: false}) - } + this.log.error('Subscription to topic ' + topicName + ' cant be established or lost. Status code: ' + e.status + ' Error: ' + e.message); + this.setState(this.topicSubscriptionData[topicName].topicKey + '.connected', {ack: true, val: false}); + }; } async createSubsrciptionObjects(topicName) { - await this.setObjectNotExists(this.topicSubscriptionData[topicName].topicKey, { type: "channel", common: { name: this.config.serverURL + '/' + topicName, role: "subscription" } }) - await this.setObjectNotExists(this.topicSubscriptionData[topicName].topicKey + '.lastMessageRaw', { type: "state", common: { name: "Last message RAW", role: "message", type: "string" } }) - await this.setObjectNotExists(this.topicSubscriptionData[topicName].topicKey + '.connected', { type: "state", common: { name: "Subscribtion state", role: "state", type: "boolean" } }) - await this.setObjectNotExists(this.topicSubscriptionData[topicName].messageKey + 'id', { type: 'state', common: { name: 'ID', role: '', type: "string" } }) - await this.setObjectNotExists(this.topicSubscriptionData[topicName].messageKey + 'tags', { type: 'state', common: { name: 'Tags', role: '', type: "string" } }) - await this.setObjectNotExists(this.topicSubscriptionData[topicName].messageKey + 'time', { type: 'state', common: { name: 'Time', role: '', type: "number" } }) - await this.setObjectNotExists(this.topicSubscriptionData[topicName].messageKey + 'event', { type: 'state', common: { name: 'Event type', role: '', type: "string" } }) - await this.setObjectNotExists(this.topicSubscriptionData[topicName].messageKey + 'title', { type: 'state', common: { name: 'Title', role: '', type: "string" } }) - await this.setObjectNotExists(this.topicSubscriptionData[topicName].messageKey + 'value', { type: 'state', common: { name: 'Content', role: '', type: "string" } }) - await this.setObjectNotExists(this.topicSubscriptionData[topicName].messageKey + 'expires', { type: 'state', common: { name: 'Expire', role: '', type: "number" } }) - await this.setObjectNotExists(this.topicSubscriptionData[topicName].messageKey + 'priority', { type: 'state', common: { name: 'Priority', role: '', type: "number" } }) + await this.setObjectNotExists(this.topicSubscriptionData[topicName].topicKey, { type: "channel", common: { name: this.config.serverURL + '/' + topicName, role: "subscription" } }); + await this.setObjectNotExists(this.topicSubscriptionData[topicName].topicKey + '.lastMessageRaw', { type: "state", common: { name: "Last message RAW", role: "message", type: "string" } }); + await this.setObjectNotExists(this.topicSubscriptionData[topicName].topicKey + '.connected', { type: "state", common: { name: "Subscribtion state", role: "state", type: "boolean" } }); + await this.setObjectNotExists(this.topicSubscriptionData[topicName].messageKey + 'id', { type: 'state', common: { name: 'ID', role: '', type: "string" } }); + await this.setObjectNotExists(this.topicSubscriptionData[topicName].messageKey + 'tags', { type: 'state', common: { name: 'Tags', role: '', type: "string" } }); + await this.setObjectNotExists(this.topicSubscriptionData[topicName].messageKey + 'time', { type: 'state', common: { name: 'Time', role: '', type: "number" } }); + await this.setObjectNotExists(this.topicSubscriptionData[topicName].messageKey + 'event', { type: 'state', common: { name: 'Event type', role: '', type: "string" } }); + await this.setObjectNotExists(this.topicSubscriptionData[topicName].messageKey + 'title', { type: 'state', common: { name: 'Title', role: '', type: "string" } }); + await this.setObjectNotExists(this.topicSubscriptionData[topicName].messageKey + 'value', { type: 'state', common: { name: 'Content', role: '', type: "string" } }); + await this.setObjectNotExists(this.topicSubscriptionData[topicName].messageKey + 'expires', { type: 'state', common: { name: 'Expire', role: '', type: "number" } }); + await this.setObjectNotExists(this.topicSubscriptionData[topicName].messageKey + 'priority', { type: 'state', common: { name: 'Priority', role: '', type: "number" } }); } async startCheckSubscriptions() { for (const [topicName, subscription] of Object.entries(this.topicSubscriptionData)) { - this.log.silly('Check subscription connection for ' + topicName) - if (subscription.eventSource === null) continue + this.log.silly('Check subscription connection for ' + topicName); + if (subscription.eventSource === null) continue; if (subscription.eventSource.readyState === 1) { - this.setState(this.topicSubscriptionData[topicName].topicKey + '.connected', {ack: true, val: true}) - continue + this.setState(this.topicSubscriptionData[topicName].topicKey + '.connected', {ack: true, val: true}); + continue; } - this.setState(this.topicSubscriptionData[topicName].topicKey + '.connected', {ack: true, val: false}) - await this.subscribeTopic(topicName, subscription.topicData.authType, subscription.topicData.username, subscription.topicData.password, subscription.topicData.accessToken) + this.setState(this.topicSubscriptionData[topicName].topicKey + '.connected', {ack: true, val: false}); + await this.subscribeTopic(topicName, subscription.topicData.authType, subscription.topicData.username, subscription.topicData.password, subscription.topicData.accessToken); } - this.checkSubscriptionsTimeout = setTimeout( () => { this.startCheckSubscriptions() }, 30000 ) + this.checkSubscriptionsTimeout = setTimeout( () => { this.startCheckSubscriptions(); }, 30000 ); } } if (require.main !== module) { - module.exports = (options) => new ntfy(options) + module.exports = (options) => new ntfy(options); } else { - new ntfy() + new ntfy(); } \ No newline at end of file