node-red-contrib-esphome 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.eslintrc.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "env": {
3
+ "node": true,
4
+ "es6": true
5
+ },
6
+ "extends": [
7
+ "eslint:recommended",
8
+ "plugin:@typescript-eslint/eslint-recommended",
9
+ "plugin:@typescript-eslint/recommended",
10
+ "plugin:prettier/recommended",
11
+ "prettier"
12
+ ],
13
+ "plugins": [
14
+ "@typescript-eslint",
15
+ "prettier"
16
+ ],
17
+ "globals": {
18
+ "Atomics": "readonly",
19
+ "SharedArrayBuffer": "readonly"
20
+ },
21
+ "parser": "@typescript-eslint/parser",
22
+ "parserOptions": {
23
+ "ecmaVersion": 2020
24
+ },
25
+ "rules": {
26
+ "prettier/prettier": "error",
27
+ "semi": "error",
28
+ "linebreak-style": ["error", "unix"],
29
+ "quotes": [
30
+ "error",
31
+ "single",
32
+ { "avoidEscape": true }
33
+ ],
34
+ "indent": [
35
+ "error",
36
+ 2
37
+ ],
38
+ "@typescript-eslint/no-explicit-any": "off"
39
+ },
40
+ "ignorePatterns":["build"]
41
+ }
@@ -0,0 +1,7 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: 'npm'
4
+ directory: '/'
5
+ schedule:
6
+ interval: 'weekly'
7
+ open-pull-requests-limit: 8
package/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ .*
2
+ *~
3
+ !.gitignore
4
+ !.github
5
+
6
+ # node
7
+ !.eslintrc.json
8
+ !.prettierrc.json
9
+ node_modules
10
+ package-lock.json
@@ -0,0 +1,10 @@
1
+ {
2
+ "tabWidth": 2,
3
+ "useTabs": false,
4
+ "arrowParens": "avoid",
5
+ "bracketSpacing": false,
6
+ "singleQuote": true,
7
+ "printWidth": 120,
8
+ "trailingComma": "none",
9
+ "endOfLine": "lf"
10
+ }
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 D
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # node-red-contrib-esphome
2
+
3
+ [![platform](https://img.shields.io/badge/platform-Node--RED-red?logo=nodered)](https://nodered.org)
4
+ [![Min Node Version](https://img.shields.io/node/v/node-red-contrib-esphome.svg)](https://nodejs.org/en/)
5
+ [![GitHub version](https://img.shields.io/github/package-json/v/twocolors/node-red-contrib-esphome?logo=npm)](https://www.npmjs.com/package/node-red-contrib-esphome)
6
+ [![GitHub stars](https://img.shields.io/github/stars/twocolors/node-red-contrib-esphome)](https://github.com/twocolors/node-red-contrib-esphome/stargazers)
7
+ [![Package Quality](https://packagequality.com/shield/node-red-contrib-esphome.svg)](https://packagequality.com/#?package=node-red-contrib-esphome)
8
+
9
+ [![issues](https://img.shields.io/github/issues/twocolors/node-red-contrib-esphome?logo=github)](https://github.com/twocolors/node-red-contrib-esphome/issues)
10
+ ![GitHub last commit](https://img.shields.io/github/last-commit/twocolors/node-red-contrib-esphome)
11
+ ![NPM Total Downloads](https://img.shields.io/npm/dt/node-red-contrib-esphome.svg)
12
+ ![NPM Downloads per month](https://img.shields.io/npm/dm/node-red-contrib-esphome)
13
+ ![Repo size](https://img.shields.io/github/repo-size/twocolors/node-red-contrib-esphome)
14
+
15
+ ## About
16
+
17
+ ### !!! Alpha, Alpha, Alpha release
18
+ ### !!! Need help writing documentation
19
+
20
+ Node-RED nodes to ESPhome devices
21
+
22
+ ## Installation
23
+
24
+ ```bash
25
+ $ npm i node-red-contrib-esphome
26
+ ```
27
+
28
+ ## Inputs
29
+
30
+ #### Button
31
+ #### Climate
32
+ - `mode` - optional. 0 - OFF, 1 - AUTO, 2 - COOL, 3 - HEAT, 4 - FAN_ONLY, 5 - DRY. See `supportedModesList` attr in config
33
+ - `targetTemperature`- optional. float
34
+ - `targetTemperatureLow`- optional. float
35
+ - `targetTemperatureHigh`- optional. float
36
+ - `legacyAway` - optional. Boolean. Deprecated: use `preset` with AWAY
37
+ - `fanMode` - optional. 0 - ON, 1 - OFF, 2 - AUTO, 3 - LOW, 4 - MEDIUM, 5 - HIGH, 6 - MIDDLE, 7 - FOCUS, 8 - DIFFUSE. See `supportedFanModesList` attr in config
38
+ - `swingMode` - optional. 0 - OFF, 1 - BOTH, 2 - VERTICAL, 3 - HORIZONTAL. See `supportedSwingModesList` attr in config
39
+ - `customFanMode` - optional. string. See `supportedCustomFanModesList` attr in config
40
+ - `preset` - optional. 0 - NONE, 1 - HOME, 2 - AWAY, 3 - BOOST, 4 - COMFORT, 5 - ECO, 6 - SLEEP, 7 - ACTIVITY. See `supportedPresetsList` attr in config
41
+ - `customPreset` - optional. string. See `supportedCustomPresetsList` attr in config
42
+ #### Cover
43
+ - `legacyCommand` - optional. 0 - OPEN, 1 - CLOSE, 2 - STOP. Deprecated: use `position`
44
+ - `position` - optional. float. 0.0 - CLOSED, 1.0 - OPEN. See `supportsPosition` attr in config
45
+ - `tilt` - optional. float. 0.0 - CLOSED, 1.0 - OPEN. See `supportsTilt` attr in config
46
+ - `stop` - optional. boolean
47
+ #### Fan
48
+ - `state` - optional. boolean
49
+ - `speed` - optional. 0 - LOW, 1 - MEDIUM, 2 - HIGH
50
+ - `oscillating` - optional. boolean
51
+ - `direction` - optional. 0 - FORWARD, 1 - REVERSE
52
+ - `speedLevel` - optional. integer. See `supportedSpeedLevels` attr in config
53
+ #### Light
54
+ - `state` - optional. boolean
55
+ - `brightness` - optional. float
56
+ - `red` - optional. integer 0-255
57
+ - `green` - optional. integer 0-255
58
+ - `blue` - optional. integer 0-255
59
+ - `colorMode` - optional. integer. See `supportedColorModesList` attr in config
60
+ - `colorBrightness` - optional. float
61
+ - `white` - optional. integer 0-255
62
+ - `colorTemperature` - optional. integer
63
+ - `coldWhite` - optional. float
64
+ - `warmWhite` - optional. float
65
+ - `flashLength` - optional. integer
66
+ - `effect` - optional. string. effect from effects array in config list
67
+ #### Lock
68
+ - `command` - REQUIRED. 0 - UNLOCK, 1 - LOCK, 2 - OPEN
69
+ - `code` - optional. string. See `requiresCode` attr in config
70
+ #### Number
71
+ - `state` - REQUIRED. float. See `minValue`, `maxValue`, and `step` attrs in config
72
+ #### Select
73
+ - `state` - REQUIRED. string. See `optionsList` attr in config
74
+ #### Siren
75
+ - `state` - REQUIRED. boolean
76
+ - `tone` - optional. string. See `tonesList` attr in config
77
+ - `duration` - optional. integer. See `supportsDuration` attr in config
78
+ - `volume` - optional. integer. See `supportsVolume` attr in config
79
+ #### Switch
80
+ - `state` - REQUIRED. boolean
81
+
82
+ ## Pictures
83
+
84
+ <img src="https://github.com/twocolors/node-red-contrib-esphome/raw/main/readme/device.png">
85
+ <img src="https://github.com/twocolors/node-red-contrib-esphome/raw/main/readme/flow.png">
@@ -0,0 +1,4 @@
1
+ export declare function discovery(name?: string, wait?: number): Promise<any>;
2
+ export declare const Status: {
3
+ [key: string]: any;
4
+ };
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.Status = exports.discovery = void 0;
13
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
14
+ const mdns = require('node-dns-sd');
15
+ // {
16
+ // address: '192.168.0.114',
17
+ // fqdn: 'corridor-waylight._esphomelib._tcp.local',
18
+ // modelName: null,
19
+ // familyName: null,
20
+ // service: { port: 6053, protocol: 'tcp', type: 'esphomelib' },
21
+ // packet: {
22
+ // header: [Object],
23
+ // questions: [],
24
+ // answers: [Array],
25
+ // authorities: [],
26
+ // additionals: [Array],
27
+ // address: '192.168.0.114'
28
+ // }
29
+ // }
30
+ function discovery(name = '_esphomelib._tcp.local', wait = 3) {
31
+ return __awaiter(this, void 0, void 0, function* () {
32
+ return yield new Promise((resolve, reject) => {
33
+ mdns
34
+ .discover({
35
+ name: name,
36
+ wait: wait
37
+ })
38
+ .then((items) => {
39
+ const devices = [];
40
+ items
41
+ .sort((a, b) => (a.fqdn > b.fqdn ? 1 : -1))
42
+ .map((device) => {
43
+ devices.push({
44
+ host: device.address,
45
+ port: device.service.port,
46
+ fqdn: device.fqdn.replace(/_esphomelib\._tcp./gi, '')
47
+ });
48
+ });
49
+ resolve(devices);
50
+ })
51
+ .catch((e) => {
52
+ reject(e);
53
+ });
54
+ });
55
+ });
56
+ }
57
+ exports.discovery = discovery;
58
+ exports.Status = {
59
+ error: {
60
+ fill: 'red',
61
+ shape: 'dot',
62
+ text: 'error'
63
+ },
64
+ disconnected: {
65
+ fill: 'red',
66
+ shape: 'ring',
67
+ text: 'disconnected'
68
+ },
69
+ connecting: {
70
+ fill: 'yellow',
71
+ shape: 'ring',
72
+ text: 'connecting'
73
+ },
74
+ connected: {
75
+ fill: 'green',
76
+ shape: 'dot',
77
+ text: 'connected'
78
+ }
79
+ };
80
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/lib/utils.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,8DAA8D;AAC9D,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;AAEpC,IAAI;AACJ,8BAA8B;AAC9B,sDAAsD;AACtD,qBAAqB;AACrB,sBAAsB;AACtB,kEAAkE;AAClE,cAAc;AACd,wBAAwB;AACxB,qBAAqB;AACrB,wBAAwB;AACxB,uBAAuB;AACvB,4BAA4B;AAC5B,+BAA+B;AAC/B,MAAM;AACN,IAAI;AAEJ,SAAsB,SAAS,CAAC,IAAI,GAAG,wBAAwB,EAAE,IAAI,GAAG,CAAC;;QACvE,OAAO,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC3C,IAAI;iBACD,QAAQ,CAAC;gBACR,IAAI,EAAE,IAAI;gBACV,IAAI,EAAE,IAAI;aACX,CAAC;iBACD,IAAI,CAAC,CAAC,KAAoB,EAAE,EAAE;gBAC7B,MAAM,OAAO,GAAkB,EAAE,CAAC;gBAElC,KAAK;qBACF,IAAI,CAAC,CAAC,CAAM,EAAE,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;qBACpD,GAAG,CAAC,CAAC,MAAW,EAAE,EAAE;oBACnB,OAAO,CAAC,IAAI,CAAC;wBACX,IAAI,EAAE,MAAM,CAAC,OAAO;wBACpB,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI;wBACzB,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,sBAAsB,EAAE,EAAE,CAAC;qBACtD,CAAC,CAAC;gBACL,CAAC,CAAC,CAAC;gBAEL,OAAO,CAAC,OAAO,CAAC,CAAC;YACnB,CAAC,CAAC;iBACD,KAAK,CAAC,CAAC,CAAQ,EAAE,EAAE;gBAClB,MAAM,CAAC,CAAC,CAAC,CAAC;YACZ,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;IACL,CAAC;CAAA;AA1BD,8BA0BC;AAEY,QAAA,MAAM,GAAyB;IAC1C,KAAK,EAAE;QACL,IAAI,EAAE,KAAK;QACX,KAAK,EAAE,KAAK;QACZ,IAAI,EAAE,OAAO;KACd;IACD,YAAY,EAAE;QACZ,IAAI,EAAE,KAAK;QACX,KAAK,EAAE,MAAM;QACb,IAAI,EAAE,cAAc;KACrB;IACD,UAAU,EAAE;QACV,IAAI,EAAE,QAAQ;QACd,KAAK,EAAE,MAAM;QACb,IAAI,EAAE,YAAY;KACnB;IACD,SAAS,EAAE;QACT,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,KAAK;QACZ,IAAI,EAAE,WAAW;KAClB;CACO,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
File without changes
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const utils_1 = require("../lib/utils");
13
+ module.exports = (RED) => {
14
+ const NODE_PATH = '/esphome/';
15
+ RED.httpAdmin.post(NODE_PATH + 'discovery', (req, res) => __awaiter(void 0, void 0, void 0, function* () {
16
+ (0, utils_1.discovery)()
17
+ .then((devices) => {
18
+ res.json(devices);
19
+ })
20
+ .catch((e) => {
21
+ res.json(e);
22
+ });
23
+ }));
24
+ RED.httpAdmin.post(NODE_PATH + 'entities', (req, res) => __awaiter(void 0, void 0, void 0, function* () {
25
+ const deviceNode = RED.nodes.getNode(req.body.deviceNode);
26
+ if (deviceNode) {
27
+ res.json(deviceNode.entities);
28
+ }
29
+ else {
30
+ res.json([]);
31
+ }
32
+ }));
33
+ };
34
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/nodes/api.ts"],"names":[],"mappings":";;;;;;;;;;;AAEA,wCAAuC;AAEvC,MAAM,CAAC,OAAO,GAAG,CAAC,GAAY,EAAE,EAAE;IAChC,MAAM,SAAS,GAAG,WAAW,CAAC;IAE9B,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,GAAG,WAAW,EAAE,CAAO,GAAoB,EAAE,GAAqB,EAAE,EAAE;QAChG,IAAA,iBAAS,GAAE;aACR,IAAI,CAAC,CAAC,OAAsB,EAAE,EAAE;YAC/B,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACpB,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,CAAQ,EAAE,EAAE;YAClB,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACd,CAAC,CAAC,CAAC;IACP,CAAC,CAAA,CAAC,CAAC;IAEH,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,GAAG,UAAU,EAAE,CAAO,GAAoB,EAAE,GAAqB,EAAE,EAAE;QAC/F,MAAM,UAAU,GAAG,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAQ,CAAC;QAEjE,IAAI,UAAU,EAAE;YACd,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;SAC/B;aAAM;YACL,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;SACd;IACH,CAAC,CAAA,CAAC,CAAC;AACL,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,147 @@
1
+ <script type="text/javascript">
2
+ RED.nodes.registerType('esphome-device', {
3
+ category: 'config',
4
+ defaults: {
5
+ name: {},
6
+ host: {value: ''},
7
+ port: {value: 6053, validate: RED.validators.number()}
8
+ },
9
+ paletteLabel: 'device',
10
+ credentials: {
11
+ password: {type: 'password'}
12
+ },
13
+ label: function () {
14
+ return this.name || 'ESPhome';
15
+ },
16
+ oneditprepare: function () {
17
+ let node = this;
18
+
19
+ function toggleSelect() {
20
+ let $val = $('#node-config-input-host').val();
21
+ $('#node-config-input-discover').html(`<i class="fa fa-search"></i>`);
22
+ $('#node-config-input-host').off('change');
23
+ $('#node-config-input-host').replaceWith(
24
+ `<input type="text" id="node-config-input-host" style="width: 100%;">`
25
+ );
26
+ $('#node-config-input-host').val($val);
27
+ }
28
+
29
+ function toggleInput() {
30
+ let $val = $('#node-config-input-host').val();
31
+ let $password = $('#node-config-input-password').val();
32
+
33
+ RED.notify(`Discovery ESPhome devices ... (~5 sec)`);
34
+
35
+ $('#node-config-input-host').prop('disabled', true);
36
+ $.post('esphome/discovery')
37
+ .done(function (data) {
38
+ if (typeof data.message !== 'undefined') {
39
+ RED.notify(data.message, 'error');
40
+ $('#node-config-input-host').prop('disabled', false);
41
+ return;
42
+ }
43
+
44
+ if (data.length === 0) {
45
+ RED.notify(`No ESPhome devices found`, 'error');
46
+ $('#node-config-input-host').prop('disabled', false);
47
+ return;
48
+ }
49
+
50
+ $('#node-config-input-discover').html(`<i class="fa fa-i-cursor"></i>`);
51
+ $('#node-config-input-host').replaceWith(
52
+ `<select id="node-config-input-host" style="width: 100%;"></select>`
53
+ );
54
+ data.map(function (d) {
55
+ $('#node-config-input-host').append(
56
+ `<option value="${d.host}" data-host="${d.host}" data-port="${d.port}" data-fqdn="${d.fqdn}">${d.fqdn}</option>`
57
+ );
58
+ });
59
+
60
+ $('#node-config-input-host').on('change', changeHost);
61
+ if (!$val || data.length === 1) {
62
+ $val = data[0].host;
63
+ }
64
+
65
+ $('#node-config-input-host').val($val);
66
+ $('#node-config-input-host').prop('disabled', false);
67
+
68
+ if ($val) {
69
+ changeHost();
70
+ }
71
+ })
72
+ .fail(function (jqxhr, textStatus, error) {
73
+ RED.notify(`Request: ${textStatus}, ${error}`, 'error');
74
+ });
75
+ }
76
+
77
+ function changeHost() {
78
+ let $elm = $('#node-config-input-host option:selected');
79
+
80
+ $('#node-config-input-port').val($elm.data('port'));
81
+ }
82
+
83
+ $('#node-config-input-discover').click(function () {
84
+ if ($('#node-config-input-host').prop('tagName') === 'INPUT') {
85
+ toggleInput();
86
+ } else {
87
+ toggleSelect();
88
+ }
89
+ });
90
+ },
91
+ oneditsave: function () {
92
+ let $elm = $('#node-config-input-host option:selected');
93
+ if (!$('#node-config-input-name').val()) {
94
+ $('#node-config-input-name').val($elm.data('fqdn'));
95
+ }
96
+ }
97
+ });
98
+ </script>
99
+
100
+ <script type="text/html" data-template-name="esphome-device">
101
+ <div class="form-row">
102
+ <label for="node-config-input-name"><i class="fa fa-tag"></i> Name</label>
103
+ <input type="text" id="node-config-input-name" placeholder="Name" />
104
+ </div>
105
+
106
+ <div class="form-row">
107
+ <label for="node-config-input-host"><i class="fa fa-globe"></i> Host</label>
108
+ <div style="display: inline-block; position: relative; width: 70%; height: 24px;">
109
+ <div style="position: absolute; left: 0; right: 42px;">
110
+ <input type="text" id="node-config-input-host" style="width: 100%;" placeholder="Host" />
111
+ </div>
112
+ <a
113
+ id="node-config-input-discover"
114
+ class="editor-button"
115
+ style="position: absolute; right: 0; top: 0; width: 33px;"
116
+ ><i class="fa fa-search"></i
117
+ ></a>
118
+ </div>
119
+ </div>
120
+
121
+ <div class="form-row">
122
+ <label for="node-config-input-port"><i class="fa fa-sign-in"></i> Port</label>
123
+ <input type="text" id="node-config-input-port" placeholder="Port" />
124
+ </div>
125
+
126
+ <div class="form-row">
127
+ <label for="node-config-input-password"><i class="fa fa-lock"></i> Password</label>
128
+ <input type="password" id="node-config-input-password" placeholder="Password" />
129
+ </div>
130
+
131
+ <div class="form-row">
132
+ <div class="form-tips"><b>Important:</b> Deploy device node to get entities list</div>
133
+ </div>
134
+ </script>
135
+
136
+ <script type="text/html" data-help-name="esphome-device">
137
+ <p>Connection to ESPhome device</p>
138
+ <h3>Configuration</h3>
139
+ <dl class="message-properties">
140
+ <dt class="required">Host<span class="property-type">string</span></dt>
141
+ <dd>host or ip address</dd>
142
+ <dt class="required">Port<span class="property-type">number</span></dt>
143
+ <dd>port</dd>
144
+ <dt class="required">Password<span class="property-type">password</span></dt>
145
+ <dd>password for API</dd>
146
+ </dl>
147
+ </script>
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
4
+ const { Client } = require('esphome-native-api');
5
+ module.exports = (RED) => {
6
+ RED.nodes.registerType('esphome-device', function (config) {
7
+ var _a;
8
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
9
+ const self = this;
10
+ self.config = config;
11
+ RED.nodes.createNode(this, config);
12
+ self.device = {};
13
+ self.entities = [];
14
+ self.current_status = 'disconnected';
15
+ if (!(config === null || config === void 0 ? void 0 : config.host) || !(config === null || config === void 0 ? void 0 : config.port) || !((_a = self.credentials) === null || _a === void 0 ? void 0 : _a.password)) {
16
+ return;
17
+ }
18
+ self.onStatus = function (string) {
19
+ self.current_status = string;
20
+ self.emit('onStatus', string);
21
+ };
22
+ self.onState = function (object) {
23
+ self.emit('onState', object);
24
+ };
25
+ self.client = new Client({
26
+ host: config.host,
27
+ port: config.port,
28
+ password: self.credentials.password,
29
+ clientInfo: 'node-red',
30
+ initializeDeviceInfo: true,
31
+ initializeListEntities: true,
32
+ initializeSubscribeStates: false,
33
+ reconnect: true,
34
+ reconnectInterval: 15 * 1000,
35
+ pingInterval: 5 * 1000
36
+ });
37
+ try {
38
+ self.client.connect();
39
+ }
40
+ catch (e) {
41
+ self.error(e.message);
42
+ return;
43
+ }
44
+ self.client.on('error', (e) => {
45
+ if (e.message.includes('EHOSTUNREACH')) {
46
+ /* empty */
47
+ }
48
+ else if (e.message.includes('Invalid password')) {
49
+ self.error(e.message);
50
+ }
51
+ else if (e.message.includes('ECONNRESET')) {
52
+ /* empty */
53
+ }
54
+ else if (e.message.includes('timeout')) {
55
+ /* empty */
56
+ }
57
+ else if (e.message.includes('write after end')) {
58
+ /* empty */
59
+ }
60
+ else {
61
+ // copy this error to issues ...
62
+ }
63
+ self.onStatus('error');
64
+ });
65
+ self.client.on('disconnected', () => {
66
+ self.onStatus('disconnected');
67
+ });
68
+ self.client.on('connected', () => {
69
+ // clear entities
70
+ self.entities = [];
71
+ self.onStatus('connecting');
72
+ });
73
+ self.client.on('initialized', () => {
74
+ self.onStatus('connected');
75
+ });
76
+ self.client.on('deviceInfo', (deviceInfo) => {
77
+ self.device = deviceInfo;
78
+ });
79
+ self.client.on('newEntity', (entity) => {
80
+ self.entities.push({
81
+ key: entity.id,
82
+ type: entity.type,
83
+ name: entity.name,
84
+ config: entity.config
85
+ });
86
+ entity.connection.subscribeStatesService();
87
+ entity.on('state', (state) => {
88
+ self.onState(Object.assign({}, state));
89
+ });
90
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
91
+ entity.on('error', (e) => {
92
+ /* empty */
93
+ });
94
+ });
95
+ self.on('close', () => {
96
+ self.client.disconnect();
97
+ });
98
+ }, {
99
+ credentials: {
100
+ password: { type: 'password' }
101
+ }
102
+ });
103
+ };
104
+ //# sourceMappingURL=device.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device.js","sourceRoot":"","sources":["../../src/nodes/device.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 90 73"><g fill="none" fill-rule="evenodd"><path d="M72.63 16.18V12c0-1.47 1.19-2.66 2.66-2.66 1.47 0 2.66 1.19 2.66 2.66v4.18m-14.27 0V12c0-1.47 1.19-2.66 2.66-2.66A2.65 2.65 0 0 1 69 11.99v4.18m-14.28.01V12c0-1.47 1.19-2.66 2.66-2.66 1.47 0 2.66 1.19 2.66 2.66v4.18m-14.28 0V12c0-1.47 1.19-2.66 2.66-2.66 1.47 0 2.66 1.19 2.66 2.66v4.18m-14.28 0V12c0-1.47 1.19-2.66 2.66-2.66 1.47 0 2.66 1.19 2.66 2.66v4.18m-14.27 0V12c0-1.47 1.19-2.66 2.66-2.66 1.47 0 2.66 1.19 2.66 2.66v4.18M77.95 56.07v4.68c0 1.47-1.19 2.66-2.66 2.66-1.47 0-2.66-1.19-2.66-2.66v-4.68m-3.63 0v4.68c0 1.47-1.19 2.66-2.66 2.66-1.47 0-2.66-1.19-2.66-2.66v-4.68m-3.64 0v4.68c0 1.47-1.19 2.66-2.66 2.66-1.47 0-2.66-1.19-2.66-2.66v-4.68m-3.64 0v4.68c0 1.47-1.19 2.66-2.66 2.66-1.47 0-2.66-1.19-2.66-2.66v-4.68m-3.64 0v4.68c0 1.47-1.19 2.66-2.66 2.66-1.47 0-2.66-1.19-2.66-2.66v-4.68m-3.63.26v4.43c0 1.47-1.19 2.66-2.66 2.66-1.47 0-2.66-1.19-2.66-2.66v-4.43" fill="#fff" stroke="#000" stroke-width="2.178"/><path fill="#fff" stroke="#000" stroke-width="2.42" d="M79.29 16.18H26.51a.97.97 0 0 0-.97.97v37.96c0 .53.43.97.97.97h52.77c.53 0 .97-.43.97-.97V17.15c0-.54-.43-.97-.96-.97z"/><path fill="#000" fill-rule="nonzero" d="M61.6 35.42v-5.07h-1.8v3.28l-6.81-6.81-11.49 11.5h2.87v7.75h17.25v-7.75h2.87z"/><path stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.961" d="M61.6 35.42v-5.07h-1.8v3.28l-6.81-6.81-11.49 11.5h2.87v7.75h17.25v-7.75h2.87z"/><path d="M25.34 53.77H9.52v-3.89h11.86v-3.89H9.52v-3.88h11.86v-3.89H9.52v-3.89h11.86v-3.88H9.52V18.47" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.159"/></g></svg>
@@ -0,0 +1 @@
1
+ export {};