├── LICENSE ├── MMM-homeassistant-sensors.js ├── README.md ├── hassio.css └── node_helper.js /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Andrew McOlash 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. 22 | -------------------------------------------------------------------------------- /MMM-homeassistant-sensors.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Module.register("MMM-homeassistant-sensors", { 4 | result: {}, 5 | defaults: { 6 | prettyName: true, 7 | stripName: true, 8 | title: "Home Assistant", 9 | host: "hassio.local", 10 | port: "8321", 11 | https: false, 12 | token: "", 13 | apipassword: "", 14 | updateInterval: 300000, 15 | displaySymbol: true, 16 | debuglogging: false, 17 | values: [] 18 | }, 19 | 20 | getStyles: function() { 21 | return [ 22 | "modules/MMM-homeassistant-sensors/MaterialDesign-Webfont-master/css/materialdesignicons.min.css", 23 | "modules/MMM-homeassistant-sensors/hassio.css" 24 | ]; 25 | }, 26 | 27 | start: function() { 28 | this.getStats(); 29 | this.scheduleUpdate(); 30 | }, 31 | isEmpty: function(obj) { 32 | for (var key in obj) { 33 | if (obj.hasOwnProperty(key)) { 34 | return false; 35 | } 36 | } 37 | return true; 38 | }, 39 | getDom: function() { 40 | var wrapper = document.createElement("ticker"); 41 | wrapper.className = "dimmed small"; 42 | var data = this.result; 43 | var statElement = document.createElement("header"); 44 | var title = this.config.title; 45 | statElement.innerHTML = title; 46 | wrapper.appendChild(statElement); 47 | 48 | if (data && !this.isEmpty(data)) { 49 | var tableElement = document.createElement("table"); 50 | var values = this.config.values; 51 | if (values.length > 0) { 52 | for (var i = 0; i < values.length; i++) { 53 | var icons = values[i].icons[0]; 54 | var sensor = values[i].sensor; 55 | var attributes = values[i].attributes; 56 | var val = this.getValue(data, sensor, attributes); 57 | var name = this.getName(data, values[i]); 58 | var unit = this.getUnit(data, sensor); 59 | var alertThreshold = values[i].alertThreshold; 60 | if (val) { 61 | tableElement.appendChild( 62 | this.addValue(name, val, unit, icons, alertThreshold) 63 | ); 64 | } 65 | } 66 | } else { 67 | for (var key in data) { 68 | if (data.hasOwnProperty(key)) { 69 | tableElement.appendChild( 70 | this.addValue(key, data[key], "", "", false) 71 | ); 72 | } 73 | } 74 | } 75 | wrapper.appendChild(tableElement); 76 | } else { 77 | var error = document.createElement("span"); 78 | error.innerHTML = "Error fetching stats."; 79 | wrapper.appendChild(error); 80 | } 81 | return wrapper; 82 | }, 83 | getValue: function(data, value, attributes=[]) { 84 | for (var i = 0; i < data.length; i++) { 85 | if (data[i].entity_id == value) { 86 | if(attributes.length==0) { 87 | return data[i].state; 88 | } 89 | var returnString = ' | '; 90 | for(var j=0; j= 0) { 206 | nextLoad = delay; 207 | } 208 | var self = this; 209 | setInterval(function() { 210 | self.getStats(); 211 | }, nextLoad); 212 | }, 213 | getStats: function() { 214 | this.sendSocketNotification("GET_STATS", this.config); 215 | }, 216 | socketNotificationReceived: function(notification, payload) { 217 | if (notification === "STATS_RESULT") { 218 | this.result = payload; 219 | var fade = 500; 220 | this.updateDom(fade); 221 | } 222 | } 223 | }); 224 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MMM-homeassistant-sensors 2 | 3 | This a module for the [MagicMirror](https://github.com/MichMich/MagicMirror/tree/develop). 4 | It can display information from [Home Assistant](https://home-assistant.io/) using the home assistant REST API. 5 | 6 | ## Installation 7 | 8 | Navigate into your MagicMirror's `modules` folder and clone this repository: 9 | `cd ~/MagicMirror/modules && git clone https://github.com/leinich/MMM-homeassistant-sensors.git` 10 | 11 | If you want to use icons for the sensors download the `MaterialDesignIcons` webfont from https://github.com/Templarian/MaterialDesign-Webfont/archive/master.zip and unzip the folder: 12 | `cd ~/MagicMirror/modules/MMM-homeassistant-sensors && wget https://github.com/Templarian/MaterialDesign-Webfont/archive/master.zip && unzip master.zip` 13 | 14 | ## Configuration 15 | 16 | It is very simple to set up this module, a sample configuration looks like this: 17 | 18 | ## Configuration Options 19 | 20 | | Option | Description | 21 | | ---------------- | ------------------------------------------------------------------------------------------------------------- | 22 | | `prettyName` | Pretty print the name of each JSON key (remove camelCase and underscores).

**Default:** `true` | 23 | | `stripName` | Removes all keys before the printed key.

**Example:** `a.b.c` will print `c`.
**Default:** `true` | 24 | | `title` | Title to display at the top of the module.

**Default:** `Home Assistant` | 25 | | `host` | The hostname or ip adress of the home assistant instance.

**Default:** `REQUIRED hassio.local` | 26 | | `port` | port of homeassistant e.g. 443 for SSL.

**Default:** `8321` | 27 | | `https` | is SSL enabled on home assistant (true/false)

**Default:** `REQUIRED false` | 28 | | `token` | The long lived token.

**Default:** `REQUIRED` | 29 | | `apipassword` | Deprecated API password.

**Default:** `` | 30 | | `updateInterval` | The time between updates (In milliseconds).

**Default:** `300000 (5 minutes)` | 31 | | `selfsigned` | allows self signed certificates/ less secure (true/false).

**Default:** `false` | 32 | | `debuglogging` | Enable logging into /home/pi/.pm2/logs/mm-error.log (true/false).

**Default:** `false` | 33 | | `values` | Specify specific values from the json feed to only show what you need (entity_id). | 34 | 35 | ## values option 36 | 37 | | Option | Description | 38 | | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 39 | | `sensor` | `entity_id` from Home Assistant. Please have a look at the states pages for the unique `entity_id` of your sensor | 40 | | `name` | The name of the value to display. If you omit this, `friendly_name` from Home Assistant will be displayed. | 41 | | `alertThreshold` | As soon as the measured value of the sensor exceeds the configured threshold, the entry will begin to 'blink'.

**Default:** `off` | 42 | | `attributes` | Array of sensor attributes to show. If not set, only show sensor state. If set, you can add as many attributes as you want, if you want to show the state as well add `'state'`.

**Default:** `[]` | 43 | | `icons` | Icons object for the on/off status of sensor. see: [MaterialDesignIcons](https://materialdesignicons.com/) | 44 | 45 | ## icons option 46 | 47 | | Option | Description | 48 | | -------------- | ---------------------------------------------------------------------------------- | 49 | | `default` | Default icon of the sensor. In case there is no on/off status, like processor use. | 50 | | `state_on` | On status icon of the sensor | 51 | | `state_off` | Off status icon of the sensor | 52 | | `state_open` | Open status icon of the sensor | 53 | | `state_closed` | Closed status icon of the sensor | 54 | 55 | Here is an example of an entry in `config.js` 56 | 57 | ``` 58 | modules: [{ 59 | module: 'MMM-homeassistant-sensors', 60 | position: 'top_left', 61 | config: { 62 | host: "YOUR_HASS_HOST", 63 | port: "8123", 64 | https: false, 65 | token: "YOUR_LONG_LIVED_HASS_TOKEN", 66 | prettyName: false, 67 | stripName: false, 68 | debuglogging: false, 69 | values: [{ 70 | sensor: "sensor.processor_use", 71 | alertThreshold: 50, 72 | icons: [{ 73 | "default": "chip" 74 | } 75 | ] 76 | }, { 77 | sensor: "binary_sensor.sensor", 78 | name: "Hallway Sensor", 79 | icons: [{ 80 | "state_off": "run", 81 | "state_on": "run-fast" 82 | } 83 | ] 84 | }, { 85 | sensor: "switch.reception_spot", 86 | icons: [{ 87 | "state_off": "lightbulb-outline", 88 | "state_on": "lightbulb-on-outline" 89 | } 90 | ] 91 | } 92 | ] 93 | 94 | } 95 | } 96 | ] 97 | ``` 98 | 99 | **Result** example: 100 | 101 | ![Alt text](https://image.ibb.co/b8edjx/dynamic_icons.png "dynamic icons example") 102 | 103 | ## Special Thanks 104 | 105 | - [Michael Teeuw](https://github.com/MichMich) for creating the awesome [MagicMirror2](https://github.com/MichMich/MagicMirror/tree/develop) project that made this module possible. 106 | - [tkoeberl](https://github.com/tkoeberl) for creating the initial module that I used as guidance in creating this module. 107 | -------------------------------------------------------------------------------- /hassio.css: -------------------------------------------------------------------------------- 1 | .blink { 2 | animation: blinker 3.5s linear infinite; 3 | } 4 | 5 | @keyframes blinker { 6 | 50% { 7 | opacity: 0; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /node_helper.js: -------------------------------------------------------------------------------- 1 | var NodeHelper = require('node_helper'); 2 | var got = require('got'); 3 | 4 | module.exports = NodeHelper.create({ 5 | start: function () { 6 | if(config.debuglogging) { console.log('MMM-homeassistant-sensors helper started...') }; 7 | }, 8 | getStats: function (config) { 9 | var self = this; 10 | var url = self.buildUrl(config); 11 | var instance = got.extend({ 12 | hooks: { 13 | beforeRequest: [ 14 | options => { 15 | if (!options.context || !options.context.token) { 16 | throw new Error('Long Lived Token required'); 17 | } 18 | json: true; 19 | options.headers = {'Authorization' : 'Bearer ' + options.context.token} 20 | } 21 | ] 22 | } 23 | }); 24 | (async () => { 25 | var context = { 26 | token: config.token 27 | }; 28 | 29 | try { 30 | var response = await instance(url, {context}); 31 | if (response.statusCode == 200) { 32 | if(config.debuglogging) { console.log('MMM-homeassistant-sensors response successfull. calling STATS_RESULT') }; 33 | self.sendSocketNotification('STATS_RESULT', JSON.parse(response.body)); 34 | } 35 | if(config.debuglogging) { 36 | console.log('MMM-homeassistant-sensors Body:', response.body); 37 | console.log('MMM-homeassistant-sensors statusCode:', response.statusCode); 38 | } 39 | } catch (error) { 40 | console.log('MMM-homeassistant-sensors - Connection Failed: ' + error.response.body); 41 | } 42 | })(); 43 | 44 | }, 45 | buildUrl: function(config) { 46 | var url = config.host; 47 | if (config.port) { 48 | url = url + ':' + config.port; 49 | } 50 | url = url + '/api/states' 51 | if (config.https) { 52 | url = 'https://' + url; 53 | } else { 54 | url = 'http://' + url; 55 | } 56 | if(config.debuglogging) { console.error("MMM-homeassistant-sensors - buildUrl:", url);} 57 | return url; 58 | }, 59 | //Subclass socketNotificationReceived received. 60 | socketNotificationReceived: function(notification, payload) { 61 | if (notification === 'GET_STATS') { 62 | this.getStats(payload); 63 | } 64 | } 65 | }); 66 | --------------------------------------------------------------------------------