commit 95fd422f788488da0942b6e822c340d1657d3989 Author: Mathias Scherer Date: Sun Apr 4 19:38:03 2021 +0200 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..40b878d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules/ \ No newline at end of file diff --git a/MMM-HomeAssistant-Touch.css b/MMM-HomeAssistant-Touch.css new file mode 100644 index 0000000..02b937a --- /dev/null +++ b/MMM-HomeAssistant-Touch.css @@ -0,0 +1,25 @@ +#MMM-HomeAssistant-Touch { + display: flex; + justify-content: center; +} + +#MMM-HomeAssistant-Touch .ha-entity { + border: 0.1rem solid grey; + border-radius: 0.5rem; + padding: 0.5rem; + margin: 0.5rem; +} + +#MMM-HomeAssistant-Touch .ha-entity .title, +#MMM-HomeAssistant-Touch .ha-entity .status { + display: block; +} + +#MMM-HomeAssistant-Touch .ha-entity.ha-switch.on, +#MMM-HomeAssistant-Touch .ha-entity.ha-light.on { + background-color: #2AF20261; +} + +body { + cursor: default; +} diff --git a/MMM-HomeAssistant-Touch.js b/MMM-HomeAssistant-Touch.js new file mode 100644 index 0000000..d9a6110 --- /dev/null +++ b/MMM-HomeAssistant-Touch.js @@ -0,0 +1,108 @@ +Module.register("MMM-HomeAssistant-Touch", { + defaults: { + host: "http://127.0.0.1", + port: 8123, + token: "NOT_VALID", + ignoreCert: false, + entities: [], + }, + // default mm functions + init, + start, + getDom, + socketNotificationReceived, + getStyles: function () { + return [this.file("MMM-HomeAssistant-Touch.css")]; + }, + getScripts: function () { + return [ + this.file("./helpers/UIClassFactory.js"), + this.file("./UIClasses/Base.js"), + this.file("./UIClasses/Light.js"), + this.file("./UIClasses/Switch.js"), + this.file("./UIClasses/Unsupported.js"), + ]; + }, + // custom functions + sendSocketNotificationHelper, + getStates, + getState, + updateState, + loadEntityClasses, +}); + +// Default MM Functions +function init() { + // rewrite sendSocketNotification function to include the identifier + this._sendSocketNotification = this.sendSocketNotification; + this.sendSocketNotification = this.sendSocketNotificationHelper; +} + +function getDom() { + var wrapper = document.createElement("div"); + wrapper.id = "MMM-HomeAssistant-Touch"; + for (const entity in this.entities) { + wrapper.appendChild(this.entities[entity].getContainer()); + } + + return wrapper; +} + +function start() { + Log.log(this.name + " is started!"); + this.loadEntityClasses(); + this.sendSocketNotification("CONNECT", { + host: this.config.host, + port: this.config.port, + token: this.config.token, + ignoreCert: this.config.ignoreCert, + }); + this.getStates(); +} + +function socketNotificationReceived(notification, payload) { + if (payload.identifier === this.identifier) { + switch (notification) { + case "GOT_STATE": + case "CHANGED_STATE": + this.updateState(payload.data); + break; + } + } +} + +// Custom Functions +function getStates() { + for (const entity of this.config.entities) { + this.getState(entity); + } +} + +function getState(entity) { + this.sendSocketNotification("GET_STATE", { entity }); +} + +function updateState(state) { + if (this.entities.hasOwnProperty(state.entity_id)) { + this.entities[state.entity_id].updateState(state); + } +} + +function sendSocketNotificationHelper(notification, payload) { + payload.identifier = this.identifier; + this._sendSocketNotification(notification, payload); +} + +// initializes each entity to render it +function loadEntityClasses() { + this.UIClassFactory = new UIClassFactory(); + this.entities = {}; + + // load UI Classes + for (const entity of this.config.entities) { + const entityClass = this.UIClassFactory.getEntityClass(entity); + if (entityClass) { + this.entities[entity] = new entityClass(entity, this); + } + } +} diff --git a/UIClasses/Base.js b/UIClasses/Base.js new file mode 100644 index 0000000..6ece783 --- /dev/null +++ b/UIClasses/Base.js @@ -0,0 +1,37 @@ +class Base { + constructor(id, mm) { + this.id = id; + this.type = id.split('.')[0] + this.name = id; + this.mm = mm; + } + + updateState(state) { + this.name = (state.attributes || {}).friendly_name || this.id; + this.state = state.state; + this.render(); + } + + getContainer() { + const entity = document.createElement("div"); + entity.classList.add("ha-entity"); + entity.classList.add(`ha-${this.type}`) + entity.id = this.id; + entity.innerHTML = "Loading..."; + return entity; + } + + render() { + const container = document.getElementById(this.id); + container.className = "" + container.classList.add("ha-entity"); + container.classList.add(`ha-${this.type}`) + + const title = document.createElement("span"); + title.className = "title"; + title.innerHTML = this.name; + + container.innerHTML = ""; + container.appendChild(title); + } +} \ No newline at end of file diff --git a/UIClasses/Light.js b/UIClasses/Light.js new file mode 100644 index 0000000..55ef3b8 --- /dev/null +++ b/UIClasses/Light.js @@ -0,0 +1,21 @@ +class Light extends Base { + getContainer() { + const entity = super.getContainer(); + entity.onclick = () => { + this.mm.sendSocketNotification("TOGGLE_STATE", { entity: this.id }); + }; + entity.ontouchend = () => { + this.mm.sendSocketNotification("TOGGLE_STATE", { entity: this.id }); + }; + + return entity; + } + + render() { + super.render(); + const container = document.getElementById(this.id); + container.classList.add(this.state); + + container.appendChild(statusCheckbox); + } +} diff --git a/UIClasses/Switch.js b/UIClasses/Switch.js new file mode 100644 index 0000000..51a7a23 --- /dev/null +++ b/UIClasses/Switch.js @@ -0,0 +1,21 @@ +class Switch extends Base { + getContainer() { + const entity = super.getContainer(); + entity.onclick = () => { + this.mm.sendSocketNotification("TOGGLE_STATE", { entity: this.id }); + }; + entity.ontouchend = () => { + this.mm.sendSocketNotification("TOGGLE_STATE", { entity: this.id }); + } + + return entity; + } + + render() { + super.render(); + const container = document.getElementById(this.id); + container.classList.add(this.state) + + container.appendChild(statusCheckbox); + } +} diff --git a/UIClasses/Unsupported.js b/UIClasses/Unsupported.js new file mode 100644 index 0000000..d936cf1 --- /dev/null +++ b/UIClasses/Unsupported.js @@ -0,0 +1,17 @@ +class Unsupported extends Base { + render() { + const container = document.getElementById(this.id); + + const title = document.createElement("span"); + title.className = "title"; + title.innerHTML = `${this.name} (Unsupported)`; + + const status = document.createElement("span"); + status.className = "status"; + status.innerHTML = this.state; + + container.innerHTML = ""; + container.appendChild(title); + container.appendChild(status); + } +} diff --git a/helpers/Logger.js b/helpers/Logger.js new file mode 100644 index 0000000..61426ad --- /dev/null +++ b/helpers/Logger.js @@ -0,0 +1,19 @@ +class Logger { + constructor(name) { + this.name = name + } + + info(...message) { + console.info(`[${this.name}]`, message) + } + + error(...message) { + console.error(`[${this.name}]`, message) + } + + debug(...message) { + console.debug(`[${this.name}]`, message) + } +} + +module.exports = Logger \ No newline at end of file diff --git a/helpers/UIClassFactory.js b/helpers/UIClassFactory.js new file mode 100644 index 0000000..38a18ae --- /dev/null +++ b/helpers/UIClassFactory.js @@ -0,0 +1,14 @@ +class UIClassFactory { + getEntityClass = function (entity_id) { + const [domain] = entity_id.split("."); + + switch (domain) { + case "light": + return Light; + case "switch": + return Switch; + default: + return Unsupported; + } + }; +} diff --git a/node_helper.js b/node_helper.js new file mode 100644 index 0000000..d7d78c8 --- /dev/null +++ b/node_helper.js @@ -0,0 +1,110 @@ +const NodeHelper = require("node_helper"); +const HomeAssistant = require("homeassistant"); +const HomeAssistantWS = require("homeassistant-ws"); +const Logger = require("./helpers/Logger"); + +const connections = {}; + +module.exports = NodeHelper.create({ + start, + socketNotificationReceived, + connect, + getState, + toggleState, + onStateChangedEvent, +}); + +function start() { + this.logger = new Logger(this.name); +} + +function socketNotificationReceived(notification, payload) { + this.logger.debug(`Recieved notification ${notification}`, payload); + if (notification !== 'CONNECT' && (!payload.identifier || !connections[payload.identifier])) { + this.logger.error(`No connection for ${payload.identifier} found`); + return; + } + + switch (notification) { + case "CONNECT": + this.connect(payload); + break; + case "GET_STATE": + this.getState(payload); + break; + case "TOGGLE_STATE": + this.toggleState(payload); + break; + } +} + +async function connect(payload) { + const connectionConfig = { + host: payload.host, + port: payload.port, + token: payload.token, + ignoreCert: payload.ignoreCert, + }; + const hass = new HomeAssistant(connectionConfig); + this.logger.info(`HomeAssistant connected for ${payload.identifier}`); + connections[payload.identifier] = { + hass, + entities: [], + }; + + const self = this; + HomeAssistantWS.default({ + ...connectionConfig, + host: new URL(connectionConfig.host).host, + }) + .then((hassWs) => { + connections[payload.identifier].websocket = hassWs; + hassWs.onStateChanged(onStateChangedEvent.bind(self)); + }) + .catch((err) => { + this.logger.error( + `WS connection for ${payload.identifier} failed with`, + err + ); + }); +} + +async function getState(payload) { + this.logger.debug(`Getting state for ${payload.entity}`); + const hass = connections[payload.identifier].hass; + const [domain, entity] = payload.entity.split("."); + const response = await hass.states.get(domain, entity); + this.logger.debug(`Got state for ${payload.entity}`); + this.sendSocketNotification("GOT_STATE", { + identifier: payload.identifier, + data: response, + }); + + if (!connections[payload.identifier].entities.includes(payload.entity)) { + connections[payload.identifier].entities.push(payload.entity); + } +} + +async function toggleState(payload) { + this.logger.debug(`Toggling state for ${payload.entity}`); + const hass = connections[payload.identifier].hass; + const [domain, entity] = payload.entity.split("."); + const response = await hass.services.call('toggle', domain, entity) + this.logger.debug(`Response for toggling state of ${payload.entity}`, response) + this.getState(payload) +} + +function onStateChangedEvent(event) { + //this.logger.debug(`Got state change for ${event.data.entity_id}`); + for (const connection in connections) { + if (connections[connection].entities.includes(event.data.entity_id)) { + this.logger.debug( + `Found listening connection (${connection}) for entity ${event.data.entity_id}` + ); + this.sendSocketNotification("CHANGED_STATE", { + identifier: connection, + data: event.data.new_state, + }); + } + } +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..09adf2a --- /dev/null +++ b/package-lock.json @@ -0,0 +1,402 @@ +{ + "name": "mmm-homeassistant-touch", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "optional": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "optional": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "optional": true + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + } + }, + "homeassistant": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/homeassistant/-/homeassistant-0.2.0.tgz", + "integrity": "sha512-kOH9PXLNOXgxcB4N3bhiO2wsgFBTVynNn3jLknnmYN4nwMTfAWrh8B4rnUFEm9dlWrnEA5XXlBCxtBiBApYGgg==", + "requires": { + "moment": "^2.24.0", + "request": "^2.88.0" + } + }, + "homeassistant-ws": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/homeassistant-ws/-/homeassistant-ws-0.1.3.tgz", + "integrity": "sha512-VnT1HVmmyEF0FI3uY5W8rXLI3hc6F1zf0qbIZlCCICPgx8y9FiIpoDBmI4TcE4SSsGCYE7YBIsXMR7hah23YJw==", + "requires": { + "buffer": "^5.6.0", + "events": "^3.1.0", + "isomorphic-ws": "^4.0.1", + "ws": "^7.2.5" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "optional": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "isomorphic-ws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "mime-db": { + "version": "1.47.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz", + "integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==" + }, + "mime-types": { + "version": "2.1.30", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz", + "integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==", + "requires": { + "mime-db": "1.47.0" + } + }, + "moment": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "requires": { + "punycode": "^2.1.0" + } + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "ws": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz", + "integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..1e0e61d --- /dev/null +++ b/package.json @@ -0,0 +1,15 @@ +{ + "name": "mmm-homeassistant-touch", + "version": "1.0.0", + "description": "", + "main": "MMM-HomeAssistant-Touch.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "Mathias Scherer ", + "license": "ISC", + "dependencies": { + "homeassistant": "^0.2.0", + "homeassistant-ws": "^0.1.3" + } +}