### 1.0.0 (2020-12-13)
* (bluefox) added the support of compact mode
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Something is not working as it should
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '...'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots & Logfiles**
|
||||
If applicable, add screenshots and logfiles to help explain your problem.
|
||||
|
||||
**Versions:**
|
||||
- Adapter version: <adapter-version>
|
||||
- JS-Controller version: <js-controller-version> <!-- determine this with `iobroker -v` on the console -->
|
||||
- Node version: <node-version> <!-- determine this with `node -v` on the console -->
|
||||
- Operating system: <os-name>
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
@@ -0,0 +1,78 @@
|
||||
# Configuration for probot-stale - https://github.com/probot/stale
|
||||
|
||||
# Number of days of inactivity before an Issue or Pull Request becomes stale
|
||||
daysUntilStale: 90
|
||||
|
||||
# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
|
||||
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
|
||||
daysUntilClose: 7
|
||||
|
||||
# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
|
||||
onlyLabels: []
|
||||
|
||||
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
|
||||
exemptLabels:
|
||||
- enhancement
|
||||
- security
|
||||
|
||||
# Set to true to ignore issues in a project (defaults to false)
|
||||
exemptProjects: true
|
||||
|
||||
# Set to true to ignore issues in a milestone (defaults to false)
|
||||
exemptMilestones: true
|
||||
|
||||
# Set to true to ignore issues with an assignee (defaults to false)
|
||||
exemptAssignees: false
|
||||
|
||||
# Label to use when marking as stale
|
||||
staleLabel: wontfix
|
||||
|
||||
# Comment to post when marking as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs within the next 7 days.
|
||||
Please check if the issue is still relevant in the most current version of the adapter
|
||||
and tell us. Also check that all relevant details, logs and reproduction steps
|
||||
are included and update them if needed.
|
||||
Thank you for your contributions.
|
||||
|
||||
Dieses Problem wurde automatisch als veraltet markiert, da es in letzter Zeit keine Aktivitäten gab.
|
||||
Es wird geschlossen, wenn nicht innerhalb der nächsten 7 Tage weitere Aktivitäten stattfinden.
|
||||
Bitte überprüft, ob das Problem auch in der aktuellsten Version des Adapters noch relevant ist,
|
||||
und teilt uns dies mit. Überprüft auch, ob alle relevanten Details, Logs und Reproduktionsschritte
|
||||
enthalten sind bzw. aktualisiert diese.
|
||||
Vielen Dank für Eure Unterstützung.
|
||||
|
||||
# Comment to post when removing the stale label.
|
||||
# unmarkComment: >
|
||||
# Your comment here.
|
||||
|
||||
# Comment to post when closing a stale Issue or Pull Request.
|
||||
closeComment: >
|
||||
This issue has been automatically closed because of inactivity. Please open a new
|
||||
issue if still relevant and make sure to include all relevant details, logs and
|
||||
reproduction steps.
|
||||
Thank you for your contributions.
|
||||
|
||||
Dieses Problem wurde aufgrund von Inaktivität automatisch geschlossen. Bitte öffnet ein
|
||||
neues Issue, falls dies noch relevant ist und stellt sicher das alle relevanten Details,
|
||||
Logs und Reproduktionsschritte enthalten sind.
|
||||
Vielen Dank für Eure Unterstützung.
|
||||
|
||||
# Limit the number of actions per hour, from 1-30. Default is 30
|
||||
limitPerRun: 30
|
||||
|
||||
# Limit to only `issues` or `pulls`
|
||||
only: issues
|
||||
|
||||
# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
|
||||
# pulls:
|
||||
# daysUntilStale: 30
|
||||
# markComment: >
|
||||
# This pull request has been automatically marked as stale because it has not had
|
||||
# recent activity. It will be closed if no further activity occurs. Thank you
|
||||
# for your contributions.
|
||||
|
||||
# issues:
|
||||
# exemptLabels:
|
||||
# - confirmed
|
||||
@@ -0,0 +1,159 @@
|
||||
# This is a composition of lint and test scripts
|
||||
# Make sure to update this file along with the others
|
||||
|
||||
name: Test and Release
|
||||
|
||||
# Run this job on all pushes and pull requests
|
||||
# as well as tags with a semantic version
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
tags:
|
||||
# normal versions
|
||||
- "v?[0-9]+.[0-9]+.[0-9]+"
|
||||
# pre-releases
|
||||
- "v?[0-9]+.[0-9]+.[0-9]+-**"
|
||||
pull_request: {}
|
||||
|
||||
jobs:
|
||||
# Performs quick checks before the expensive test runs
|
||||
check-and-lint:
|
||||
if: contains(github.event.head_commit.message, '[skip ci]') == false
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm install
|
||||
|
||||
# - name: Perform a type check
|
||||
# run: npm run check:ts
|
||||
# env:
|
||||
# CI: true
|
||||
# - name: Lint TypeScript code
|
||||
# run: npm run lint
|
||||
# - name: Test package files
|
||||
# run: npm run test:package
|
||||
|
||||
# Runs adapter tests on all supported node versions and OSes
|
||||
adapter-tests:
|
||||
if: contains(github.event.head_commit.message, '[skip ci]') == false
|
||||
|
||||
needs: [check-and-lint]
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [10.x, 12.x, 14.x]
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Run local tests
|
||||
run: npm test
|
||||
# - name: Run unit tests
|
||||
# run: npm run test:unit
|
||||
# - name: Run integration tests # (linux/osx)
|
||||
# if: startsWith(runner.OS, 'windows') == false
|
||||
# run: DEBUG=testing:* npm run test:integration
|
||||
# - name: Run integration tests # (windows)
|
||||
# if: startsWith(runner.OS, 'windows')
|
||||
# run: set DEBUG=testing:* & npm run test:integration
|
||||
|
||||
# Deploys the final package to NPM
|
||||
deploy:
|
||||
needs: [adapter-tests]
|
||||
|
||||
# Trigger this step only when a commit on master is tagged with a version number
|
||||
if: |
|
||||
contains(github.event.head_commit.message, '[skip ci]') == false &&
|
||||
github.event_name == 'push' &&
|
||||
github.event.base_ref == 'refs/heads/master' &&
|
||||
startsWith(github.ref, 'refs/tags/')
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12.x]
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: Extract the version and commit body from the tag
|
||||
id: extract_release
|
||||
# The body may be multiline, therefore we need to escape some characters
|
||||
run: |
|
||||
VERSION="${{ github.ref }}"
|
||||
VERSION=${VERSION##*/}
|
||||
VERSION=${VERSION##*v}
|
||||
echo "::set-output name=VERSION::$VERSION"
|
||||
BODY=$(git show -s --format=%b)
|
||||
BODY="${BODY//'%'/'%25'}"
|
||||
BODY="${BODY//$'\n'/'%0A'}"
|
||||
BODY="${BODY//$'\r'/'%0D'}"
|
||||
echo "::set-output name=BODY::$BODY"
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm install
|
||||
|
||||
# - name: Create a clean build
|
||||
# run: npm run build
|
||||
- name: Publish package to npm
|
||||
run: |
|
||||
npm config set //registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}
|
||||
npm whoami
|
||||
npm publish
|
||||
|
||||
- name: Create Github Release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: Release v${{ steps.extract_release.outputs.VERSION }}
|
||||
draft: false
|
||||
# Prerelease versions create prereleases on Github
|
||||
prerelease: ${{ contains(steps.extract_release.outputs.VERSION, '-') }}
|
||||
body: ${{ steps.extract_release.outputs.BODY }}
|
||||
|
||||
#- name: Notify Sentry.io about the release
|
||||
# run: |
|
||||
# npm i -g @sentry/cli
|
||||
# export SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
# export SENTRY_URL=https://sentry.iobroker.net
|
||||
# export SENTRY_ORG=iobroker
|
||||
# export SENTRY_PROJECT=iobroker-hass
|
||||
# export SENTRY_VERSION=iobroker.hass@${{ steps.extract_release.outputs.VERSION }}
|
||||
# sentry-cli releases new $SENTRY_VERSION
|
||||
# sentry-cli releases finalize $SENTRY_VERSION
|
||||
|
||||
# Add the following line BEFORE finalize if repositories are connected in Sentry
|
||||
# sentry-cli releases set-commits $SENTRY_VERSION --auto
|
||||
|
||||
# Add the following line BEFORE finalize if sourcemap uploads are needed
|
||||
# sentry-cli releases files $SENTRY_VERSION upload-sourcemaps build/
|
||||
+11
-8
@@ -1,9 +1,12 @@
|
||||
/**/*
|
||||
/gulpfile.js
|
||||
gulpfile.js
|
||||
tasks
|
||||
tmp
|
||||
test
|
||||
.travis.yml
|
||||
appveyor.yml
|
||||
admin/i18n
|
||||
iob_npm.done
|
||||
package-lock.json
|
||||
!/admin/**/*
|
||||
!/admin/*
|
||||
!/lib/**/*
|
||||
!/lib/*
|
||||
!/io-package.json
|
||||
!/package.json
|
||||
!/LICENSE
|
||||
!/main.js
|
||||
!/README.md
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018 bluefox <dogafox@gmail.com>
|
||||
Copyright (c) 2018-2020 bluefox <dogafox@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -1,23 +1,38 @@
|
||||

|
||||
# ioBroker.hass
|
||||
=================
|
||||
|
||||
[](https://www.npmjs.com/package/iobroker.hass)
|
||||
[](https://www.npmjs.com/package/iobroker.hass)
|
||||
|
||||
[](https://nodei.co/npm/iobroker.hass/)
|
||||
|
||||
This adapter allows the connecting of Home Assistant to ioBroker.
|
||||
|
||||
This adapter allows connect Home Assistant to ioBroker.
|
||||
## Usage
|
||||
Create a long term token in HASS and use it as PW (copy it also in the repeat field).
|
||||
|
||||
## Configuration
|
||||
There is a good article about connection.
|
||||
|
||||
Please check it https://www.smarthomejetzt.de/mit-iobroker-auf-eine-home-assistant-hass-io-installation-und-die-geraete-zugreifen/
|
||||
|
||||
**Unfortunately only in german, but the [google translate works rather good](https://translate.google.com/translate?hl=en&sl=de&tl=en&u=https%3A%2F%2Fwww.smarthomejetzt.de%2Fmit-iobroker-auf-eine-home-assistant-hass-io-installation-und-die-geraete-zugreifen%2F)**
|
||||
|
||||
<!--
|
||||
Placeholder for the next version (at the beginning of the line):
|
||||
### __WORK IN PROGRESS__
|
||||
-->
|
||||
|
||||
## Changelog
|
||||
#### 0.1.0
|
||||
### 1.0.0 (2020-12-13)
|
||||
* (bluefox) added the support of compact mode
|
||||
|
||||
### 0.1.0
|
||||
* (bluefox) initial release
|
||||
|
||||
## License
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018 bluefox <dogafox@gmail.com>
|
||||
Copyright (c) 2018-2020 bluefox <dogafox@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
+1
-2
@@ -56,12 +56,11 @@
|
||||
callback(obj);
|
||||
}
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div id="adapter-container">
|
||||
<table><tr>
|
||||
<td><img src="hass.png"/></td>
|
||||
<td><img src="hass.png" alt="logo"/></td>
|
||||
<td><h3 class="translate">Home assistant adapter settings</h3></td>
|
||||
</tr></table>
|
||||
<table>
|
||||
|
||||
+88
-86
@@ -1,10 +1,10 @@
|
||||
'use strict';
|
||||
|
||||
var gulp = require('gulp');
|
||||
var fs = require('fs');
|
||||
var pkg = require('./package.json');
|
||||
var iopackage = require('./io-package.json');
|
||||
var version = (pkg && pkg.version) ? pkg.version : iopackage.common.version;
|
||||
const gulp = require('gulp');
|
||||
const fs = require('fs');
|
||||
const pkg = require('./package.json');
|
||||
const iopackage = require('./io-package.json');
|
||||
const version = (pkg && pkg.version) ? pkg.version : iopackage.common.version;
|
||||
/*var appName = getAppName();
|
||||
|
||||
function getAppName() {
|
||||
@@ -13,7 +13,7 @@ function getAppName() {
|
||||
}
|
||||
*/
|
||||
const fileName = 'words.js';
|
||||
var languages = {
|
||||
let languages = {
|
||||
en: {},
|
||||
de: {},
|
||||
ru: {},
|
||||
@@ -22,24 +22,27 @@ var languages = {
|
||||
fr: {},
|
||||
it: {},
|
||||
es: {},
|
||||
pl: {}
|
||||
pl: {},
|
||||
'zh-cn': {}
|
||||
};
|
||||
|
||||
function lang2data(lang, isFlat) {
|
||||
var str = isFlat ? '' : '{\n';
|
||||
var count = 0;
|
||||
for (var w in lang) {
|
||||
let str = isFlat ? '' : '{\n';
|
||||
let count = 0;
|
||||
for (const w in lang) {
|
||||
if (lang.hasOwnProperty(w)) {
|
||||
count++;
|
||||
if (isFlat) {
|
||||
str += (lang[w] === '' ? (isFlat[w] || w) : lang[w]) + '\n';
|
||||
} else {
|
||||
var key = ' "' + w.replace(/"/g, '\\"') + '": ';
|
||||
const key = ' "' + w.replace(/"/g, '\\"') + '": ';
|
||||
str += key + '"' + lang[w].replace(/"/g, '\\"') + '",\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!count) return isFlat ? '' : '{\n}';
|
||||
if (!count) {
|
||||
return isFlat ? '' : '{\n}';
|
||||
}
|
||||
if (isFlat) {
|
||||
return str;
|
||||
} else {
|
||||
@@ -49,15 +52,15 @@ function lang2data(lang, isFlat) {
|
||||
|
||||
function readWordJs(src) {
|
||||
try {
|
||||
var words;
|
||||
let words;
|
||||
if (fs.existsSync(src + 'js/' + fileName)) {
|
||||
words = fs.readFileSync(src + 'js/' + fileName).toString();
|
||||
} else {
|
||||
words = fs.readFileSync(src + fileName).toString();
|
||||
}
|
||||
|
||||
var lines = words.split(/\r\n|\r|\n/g);
|
||||
var i = 0;
|
||||
const lines = words.split(/\r\n|\r|\n/g);
|
||||
let i = 0;
|
||||
while (!lines[i].match(/^systemDictionary = {/)) {
|
||||
i++;
|
||||
}
|
||||
@@ -75,7 +78,7 @@ function readWordJs(src) {
|
||||
lines[0] = lines[0].replace('systemDictionary = ', '');
|
||||
lines[lines.length - 1] = lines[lines.length - 1].trim().replace(/};$/, '}');
|
||||
words = lines.join('\n');
|
||||
var resultFunc = new Function('return ' + words + ';');
|
||||
const resultFunc = new Function('return ' + words + ';');
|
||||
|
||||
return resultFunc();
|
||||
} catch (e) {
|
||||
@@ -86,16 +89,16 @@ function padRight(text, totalLength) {
|
||||
return text + (text.length < totalLength ? new Array(totalLength - text.length).join(' ') : '');
|
||||
}
|
||||
function writeWordJs(data, src) {
|
||||
var text = '// DO NOT EDIT THIS FILE!!! IT WILL BE AUTOMATICALLY GENERATED FROM src/i18n\n';
|
||||
let text = '// DO NOT EDIT THIS FILE!!! IT WILL BE AUTOMATICALLY GENERATED FROM src/i18n\n';
|
||||
text += '/*global systemDictionary:true */\n';
|
||||
text += '\'use strict\';\n\n';
|
||||
|
||||
text += 'systemDictionary = {\n';
|
||||
for (var word in data) {
|
||||
for (const word in data) {
|
||||
if (data.hasOwnProperty(word)) {
|
||||
text += ' ' + padRight('"' + word.replace(/"/g, '\\"') + '": {', 50);
|
||||
var line = '';
|
||||
for (var lang in data[word]) {
|
||||
let line = '';
|
||||
for (const lang in data[word]) {
|
||||
if (data[word].hasOwnProperty(lang)) {
|
||||
line += '"' + lang + '": "' + padRight(data[word][lang].replace(/"/g, '\\"') + '",', 50) + ' ';
|
||||
}
|
||||
@@ -120,16 +123,16 @@ function writeWordJs(data, src) {
|
||||
const EMPTY = '';
|
||||
|
||||
function words2languages(src) {
|
||||
var langs = Object.assign({}, languages);
|
||||
var data = readWordJs(src);
|
||||
const langs = Object.assign({}, languages);
|
||||
const data = readWordJs(src);
|
||||
if (data) {
|
||||
for (var word in data) {
|
||||
for (const word in data) {
|
||||
if (data.hasOwnProperty(word)) {
|
||||
for (var lang in data[word]) {
|
||||
for (const lang in data[word]) {
|
||||
if (data[word].hasOwnProperty(lang)) {
|
||||
langs[lang][word] = data[word][lang];
|
||||
// pre-fill all other languages
|
||||
for (var j in langs) {
|
||||
for (const j in langs) {
|
||||
if (langs.hasOwnProperty(j)) {
|
||||
langs[j][word] = langs[j][word] || EMPTY;
|
||||
}
|
||||
@@ -141,12 +144,12 @@ function words2languages(src) {
|
||||
if (!fs.existsSync(src + 'i18n/')) {
|
||||
fs.mkdirSync(src + 'i18n/');
|
||||
}
|
||||
for (var l in langs) {
|
||||
for (const l in langs) {
|
||||
if (!langs.hasOwnProperty(l)) continue;
|
||||
var keys = Object.keys(langs[l]);
|
||||
const keys = Object.keys(langs[l]);
|
||||
//keys.sort();
|
||||
var obj = {};
|
||||
for (var k = 0; k < keys.length; k++) {
|
||||
let obj = {};
|
||||
for (let k = 0; k < keys.length; k++) {
|
||||
obj[keys[k]] = langs[l][keys[k]];
|
||||
}
|
||||
if (!fs.existsSync(src + 'i18n/' + l)) {
|
||||
@@ -160,16 +163,16 @@ function words2languages(src) {
|
||||
}
|
||||
}
|
||||
function words2languagesFlat(src) {
|
||||
var langs = Object.assign({}, languages);
|
||||
var data = readWordJs(src);
|
||||
let langs = Object.assign({}, languages);
|
||||
const data = readWordJs(src);
|
||||
if (data) {
|
||||
for (var word in data) {
|
||||
for (const word in data) {
|
||||
if (data.hasOwnProperty(word)) {
|
||||
for (var lang in data[word]) {
|
||||
for (const lang in data[word]) {
|
||||
if (data[word].hasOwnProperty(lang)) {
|
||||
langs[lang][word] = data[word][lang];
|
||||
// pre-fill all other languages
|
||||
for (var j in langs) {
|
||||
for (const j in langs) {
|
||||
if (langs.hasOwnProperty(j)) {
|
||||
langs[j][word] = langs[j][word] || EMPTY;
|
||||
}
|
||||
@@ -178,12 +181,12 @@ function words2languagesFlat(src) {
|
||||
}
|
||||
}
|
||||
}
|
||||
var keys = Object.keys(langs.en);
|
||||
const keys = Object.keys(langs.en);
|
||||
//keys.sort();
|
||||
for (var l in langs) {
|
||||
for (const l in langs) {
|
||||
if (!langs.hasOwnProperty(l)) continue;
|
||||
var obj = {};
|
||||
for (var k = 0; k < keys.length; k++) {
|
||||
let obj = {};
|
||||
for (let k = 0; k < keys.length; k++) {
|
||||
obj[keys[k]] = langs[l][keys[k]];
|
||||
}
|
||||
langs[l] = obj;
|
||||
@@ -191,7 +194,7 @@ function words2languagesFlat(src) {
|
||||
if (!fs.existsSync(src + 'i18n/')) {
|
||||
fs.mkdirSync(src + 'i18n/');
|
||||
}
|
||||
for (var ll in langs) {
|
||||
for (const ll in langs) {
|
||||
if (!langs.hasOwnProperty(ll)) continue;
|
||||
if (!fs.existsSync(src + 'i18n/' + ll)) {
|
||||
fs.mkdirSync(src + 'i18n/' + ll);
|
||||
@@ -205,13 +208,13 @@ function words2languagesFlat(src) {
|
||||
}
|
||||
}
|
||||
function languagesFlat2words(src) {
|
||||
var dirs = fs.readdirSync(src + 'i18n/');
|
||||
var langs = {};
|
||||
var bigOne = {};
|
||||
var order = Object.keys(languages);
|
||||
dirs.sort(function (a, b) {
|
||||
var posA = order.indexOf(a);
|
||||
var posB = order.indexOf(b);
|
||||
const dirs = fs.readdirSync(src + 'i18n/');
|
||||
let langs = {};
|
||||
let bigOne = {};
|
||||
const order = Object.keys(languages);
|
||||
dirs.sort((a, b) => {
|
||||
const posA = order.indexOf(a);
|
||||
const posB = order.indexOf(b);
|
||||
if (posA === -1 && posB === -1) {
|
||||
if (a > b) return 1;
|
||||
if (a < b) return -1;
|
||||
@@ -226,19 +229,19 @@ function languagesFlat2words(src) {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
var keys = fs.readFileSync(src + 'i18n/flat.txt').toString().split('\n');
|
||||
const keys = fs.readFileSync(src + 'i18n/flat.txt').toString().split('\n');
|
||||
|
||||
for (var l = 0; l < dirs.length; l++) {
|
||||
for (let l = 0; l < dirs.length; l++) {
|
||||
if (dirs[l] === 'flat.txt') continue;
|
||||
var lang = dirs[l];
|
||||
var values = fs.readFileSync(src + 'i18n/' + lang + '/flat.txt').toString().split('\n');
|
||||
let lang = dirs[l];
|
||||
const values = fs.readFileSync(src + 'i18n/' + lang + '/flat.txt').toString().split('\n');
|
||||
langs[lang] = {};
|
||||
keys.forEach(function (word, i) {
|
||||
langs[lang][word] = values[i].replace(/<\/ i>/g, '</i>').replace(/<\/ b>/g, '</b>').replace(/<\/ span>/g, '</span>').replace(/% s/g, ' %s');
|
||||
});
|
||||
|
||||
var words = langs[lang];
|
||||
for (var word in words) {
|
||||
const words = langs[lang];
|
||||
for (const word in words) {
|
||||
if (words.hasOwnProperty(word)) {
|
||||
bigOne[word] = bigOne[word] || {};
|
||||
if (words[word] !== EMPTY) {
|
||||
@@ -248,12 +251,12 @@ function languagesFlat2words(src) {
|
||||
}
|
||||
}
|
||||
// read actual words.js
|
||||
var aWords = readWordJs();
|
||||
const aWords = readWordJs();
|
||||
|
||||
var temporaryIgnore = ['pt', 'fr', 'nl', 'flat.txt'];
|
||||
const temporaryIgnore = ['pt', 'fr', 'nl', 'flat.txt'];
|
||||
if (aWords) {
|
||||
// Merge words together
|
||||
for (var w in aWords) {
|
||||
for (const w in aWords) {
|
||||
if (aWords.hasOwnProperty(w)) {
|
||||
if (!bigOne[w]) {
|
||||
console.warn('Take from actual words.js: ' + w);
|
||||
@@ -273,13 +276,13 @@ function languagesFlat2words(src) {
|
||||
writeWordJs(bigOne, src);
|
||||
}
|
||||
function languages2words(src) {
|
||||
var dirs = fs.readdirSync(src + 'i18n/');
|
||||
var langs = {};
|
||||
var bigOne = {};
|
||||
var order = Object.keys(languages);
|
||||
dirs.sort(function (a, b) {
|
||||
var posA = order.indexOf(a);
|
||||
var posB = order.indexOf(b);
|
||||
const dirs = fs.readdirSync(src + 'i18n/');
|
||||
let langs = {};
|
||||
let bigOne = {};
|
||||
const order = Object.keys(languages);
|
||||
dirs.sort((a, b) => {
|
||||
const posA = order.indexOf(a);
|
||||
const posB = order.indexOf(b);
|
||||
if (posA === -1 && posB === -1) {
|
||||
if (a > b) return 1;
|
||||
if (a < b) return -1;
|
||||
@@ -294,13 +297,13 @@ function languages2words(src) {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
for (var l = 0; l < dirs.length; l++) {
|
||||
for (let l = 0; l < dirs.length; l++) {
|
||||
if (dirs[l] === 'flat.txt') continue;
|
||||
var lang = dirs[l];
|
||||
const lang = dirs[l];
|
||||
langs[lang] = fs.readFileSync(src + 'i18n/' + lang + '/translations.json').toString();
|
||||
langs[lang] = JSON.parse(langs[lang]);
|
||||
var words = langs[lang];
|
||||
for (var word in words) {
|
||||
const words = langs[lang];
|
||||
for (const word in words) {
|
||||
if (words.hasOwnProperty(word)) {
|
||||
bigOne[word] = bigOne[word] || {};
|
||||
if (words[word] !== EMPTY) {
|
||||
@@ -310,12 +313,12 @@ function languages2words(src) {
|
||||
}
|
||||
}
|
||||
// read actual words.js
|
||||
var aWords = readWordJs();
|
||||
const aWords = readWordJs();
|
||||
|
||||
var temporaryIgnore = ['pt', 'fr', 'nl', 'it'];
|
||||
const temporaryIgnore = ['pt', 'fr', 'nl', 'it'];
|
||||
if (aWords) {
|
||||
// Merge words together
|
||||
for (var w in aWords) {
|
||||
for (const w in aWords) {
|
||||
if (aWords.hasOwnProperty(w)) {
|
||||
if (!bigOne[w]) {
|
||||
console.warn('Take from actual words.js: ' + w);
|
||||
@@ -335,33 +338,32 @@ function languages2words(src) {
|
||||
writeWordJs(bigOne, src);
|
||||
}
|
||||
|
||||
gulp.task('adminWords2languages', function (done) {
|
||||
gulp.task('admin (words.js => json)', done => {
|
||||
words2languages('./admin/');
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task('adminWords2languagesFlat', function (done) {
|
||||
gulp.task('admin (words.js => flat)', done => {
|
||||
words2languagesFlat('./admin/');
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task('adminLanguagesFlat2words', function (done) {
|
||||
gulp.task('admin (flat => words.js)', done => {
|
||||
languagesFlat2words('./admin/');
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task('adminLanguages2words', function (done) {
|
||||
gulp.task('admin (json => words.js)', done => {
|
||||
languages2words('./admin/');
|
||||
done();
|
||||
});
|
||||
|
||||
|
||||
gulp.task('updatePackages', function (done) {
|
||||
gulp.task('updatePackages', done => {
|
||||
iopackage.common.version = pkg.version;
|
||||
iopackage.common.news = iopackage.common.news || {};
|
||||
if (!iopackage.common.news[pkg.version]) {
|
||||
var news = iopackage.common.news;
|
||||
var newNews = {};
|
||||
const news = iopackage.common.news;
|
||||
let newNews = {};
|
||||
|
||||
newNews[pkg.version] = {
|
||||
en: 'news',
|
||||
@@ -374,20 +376,20 @@ gulp.task('updatePackages', function (done) {
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task('updateReadme', function (done) {
|
||||
var readme = fs.readFileSync('README.md').toString();
|
||||
var pos = readme.indexOf('## Changelog\n');
|
||||
gulp.task('updateReadme', done => {
|
||||
const readme = fs.readFileSync('README.md').toString();
|
||||
const pos = readme.indexOf('## Changelog\n');
|
||||
if (pos !== -1) {
|
||||
var readmeStart = readme.substring(0, pos + '## Changelog\n'.length);
|
||||
var readmeEnd = readme.substring(pos + '## Changelog\n'.length);
|
||||
let readmeStart = readme.substring(0, pos + '## Changelog\n'.length);
|
||||
let readmeEnd = readme.substring(pos + '## Changelog\n'.length);
|
||||
|
||||
if (readme.indexOf(version) === -1) {
|
||||
var timestamp = new Date();
|
||||
var date = timestamp.getFullYear() + '-' +
|
||||
const timestamp = new Date();
|
||||
const date = timestamp.getFullYear() + '-' +
|
||||
('0' + (timestamp.getMonth() + 1).toString(10)).slice(-2) + '-' +
|
||||
('0' + (timestamp.getDate()).toString(10)).slice(-2);
|
||||
|
||||
var news = '';
|
||||
let news = '';
|
||||
if (iopackage.common.news && iopackage.common.news[pkg.version]) {
|
||||
news += '* ' + iopackage.common.news[pkg.version].en;
|
||||
}
|
||||
@@ -398,4 +400,4 @@ gulp.task('updateReadme', function (done) {
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task('default', ['updatePackages', 'updateReadme']);
|
||||
gulp.task('default', gulp.series('updatePackages', 'updateReadme'));
|
||||
+22
-4
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"common": {
|
||||
"name": "hass",
|
||||
"version": "0.1.0",
|
||||
"version": "1.0.0",
|
||||
"title": "Home Assistant",
|
||||
"desc": {
|
||||
"en": "Home Assistant connection for ioBroker",
|
||||
@@ -15,7 +15,19 @@
|
||||
"pl": "Połączenie Home Assistant dla ioBroker"
|
||||
},
|
||||
"news": {
|
||||
"0.1.0" : {
|
||||
"1.0.0": {
|
||||
"en": "added the support of compact mode",
|
||||
"de": "fügte die Unterstützung des Kompaktmodus hinzu",
|
||||
"ru": "добавлена поддержка компактного режима",
|
||||
"pt": "adicionado o suporte do modo compacto",
|
||||
"nl": "de ondersteuning van de compacte modus toegevoegd",
|
||||
"fr": "ajouté le support du mode compact",
|
||||
"it": "aggiunto il supporto della modalità compatta",
|
||||
"es": "agregó el soporte del modo compacto",
|
||||
"pl": "dodano obsługę trybu kompaktowego",
|
||||
"zh-cn": "增加了对紧凑模式的支持"
|
||||
},
|
||||
"0.1.0": {
|
||||
"en": "initial version",
|
||||
"de": "erste Version",
|
||||
"ru": "Первоначальная версия",
|
||||
@@ -32,8 +44,15 @@
|
||||
"mode": "daemon",
|
||||
"icon": "hass.png",
|
||||
"enabled": true,
|
||||
"compact": true,
|
||||
"materialize": true,
|
||||
"license": "MIT",
|
||||
"extIcon": "https://raw.githubusercontent.com/ioBroker/ioBroker.hass/master/admin/hass.png",
|
||||
"keywords": ["HASS", "Home", "assistant"],
|
||||
"keywords": [
|
||||
"HASS",
|
||||
"Home",
|
||||
"assistant"
|
||||
],
|
||||
"readme": "https://github.com/ioBroker/ioBroker.hass/blob/master/README.md",
|
||||
"loglevel": "info",
|
||||
"type": "iot-systems",
|
||||
@@ -48,7 +67,6 @@
|
||||
"secure": false
|
||||
},
|
||||
"objects": [
|
||||
|
||||
],
|
||||
"instanceObjects": [
|
||||
{
|
||||
|
||||
+37
-50
@@ -1,30 +1,32 @@
|
||||
var util = require('util');
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var WebSocket = require('ws');
|
||||
const util = require('util');
|
||||
const EventEmitter = require('events').EventEmitter;
|
||||
const WebSocket = require('ws');
|
||||
|
||||
function HASS(options, log) {
|
||||
if (!(this instanceof HASS)) return new HASS(options);
|
||||
if (!(this instanceof HASS)) {
|
||||
return new HASS(options);
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
options.host = options.host || '127.0.0.1';
|
||||
options.port = parseInt(options.port, 10) || 8123;
|
||||
|
||||
var ERRORS = {
|
||||
const ERRORS = {
|
||||
1: 'ERR_CANNOT_CONNECT',
|
||||
2: 'ERR_INVALID_AUTH',
|
||||
3: 'ERR_CONNECTION_LOST'
|
||||
};
|
||||
|
||||
this.socket = null;
|
||||
var that = this;
|
||||
var currentId = 1;
|
||||
var requests = {};
|
||||
var connected;
|
||||
var connectTimeout = null;
|
||||
const that = this;
|
||||
let currentId = 1;
|
||||
const requests = {};
|
||||
let connected;
|
||||
let connectTimeout = null;
|
||||
|
||||
function subscribeEvents(socket, callback) {
|
||||
if (socket && typeof socket.send === 'function') {
|
||||
var id = currentId++;
|
||||
const id = currentId++;
|
||||
requests[id] = {type: 'subscribe_events', ts: Date.now(), cb: callback};
|
||||
|
||||
socket.send(JSON.stringify({
|
||||
@@ -39,7 +41,7 @@ function HASS(options, log) {
|
||||
|
||||
function getConfig(socket, callback) {
|
||||
if (socket && typeof socket.send === 'function') {
|
||||
var id = currentId++;
|
||||
const id = currentId++;
|
||||
requests[id] = {type: 'get_config', cb: callback, ts: Date.now()};
|
||||
socket.send(JSON.stringify({
|
||||
id: id,
|
||||
@@ -52,7 +54,7 @@ function HASS(options, log) {
|
||||
|
||||
function getStates(socket, callback) {
|
||||
if (socket && typeof socket.send === 'function') {
|
||||
var id = currentId++;
|
||||
const id = currentId++;
|
||||
requests[id] = {type: 'get_states', cb: callback, ts: Date.now()};
|
||||
socket.send(JSON.stringify({
|
||||
id: id,
|
||||
@@ -65,7 +67,7 @@ function HASS(options, log) {
|
||||
|
||||
function getPanels(socket, callback) {
|
||||
if (socket && typeof socket.send === 'function') {
|
||||
var id = currentId++;
|
||||
const id = currentId++;
|
||||
requests[id] = {type: 'get_panels', cb: callback, ts: Date.now()};
|
||||
socket.send(JSON.stringify({
|
||||
id: id,
|
||||
@@ -78,7 +80,7 @@ function HASS(options, log) {
|
||||
|
||||
function getServices(socket, callback) {
|
||||
if (socket && typeof socket.send === 'function') {
|
||||
var id = currentId++;
|
||||
const id = currentId++;
|
||||
requests[id] = {type: 'get_services', cb: callback, ts: Date.now()};
|
||||
socket.send(JSON.stringify({
|
||||
id: id,
|
||||
@@ -91,7 +93,7 @@ function HASS(options, log) {
|
||||
|
||||
function callService(socket, service, domain, serviceData, callback) {
|
||||
if (socket && typeof socket.send === 'function') {
|
||||
var id = currentId++;
|
||||
const id = currentId++;
|
||||
requests[id] = {type: 'call_service', cb: callback, ts: Date.now()};
|
||||
socket.send(JSON.stringify({
|
||||
id: id,
|
||||
@@ -115,10 +117,10 @@ function HASS(options, log) {
|
||||
}
|
||||
|
||||
function initSocket(socket) {
|
||||
socket.on('message', function (msg) {
|
||||
socket.on('message', msg => {
|
||||
log.silly(msg);
|
||||
|
||||
var response = JSON.parse(msg);
|
||||
const response = JSON.parse(msg);
|
||||
if (response.type === 'event') {
|
||||
if (response.event.data && response.event.event_type === 'system_log_event') {
|
||||
if (response.event.data.level === 'WARNING') {
|
||||
@@ -138,25 +140,22 @@ function HASS(options, log) {
|
||||
that.emit('error', 'Password required. Connection closed');
|
||||
socket.terminate();
|
||||
} else {
|
||||
setTimeout(function () {
|
||||
sendAuth(socket, options.password);
|
||||
}, 50);
|
||||
setTimeout(() => sendAuth(socket, options.password), 50);
|
||||
}
|
||||
} else
|
||||
if (response.type === 'auth_ok') {
|
||||
setImmediate(function () {
|
||||
subscribeEvents(socket, function (err) {
|
||||
setImmediate(() =>
|
||||
subscribeEvents(socket, err => {
|
||||
if (!err) {
|
||||
connected = true;
|
||||
that.emit('connected');
|
||||
}
|
||||
});
|
||||
});
|
||||
}));
|
||||
} else if (response.id === undefined) {
|
||||
log.error('Invalid answer: ' + msg);
|
||||
log.error(`Invalid answer: ${msg}`);
|
||||
} else {
|
||||
if (response.type === 'result' && requests[response.id]) {
|
||||
log.debug('got answer for ' + requests[response.id].type);
|
||||
log.debug(`got answer for ${requests[response.id].type}`);
|
||||
if (typeof requests[response.id].cb === 'function') {
|
||||
requests[response.id].cb(!response.success, response.result);
|
||||
delete requests[response.id];
|
||||
@@ -165,7 +164,7 @@ function HASS(options, log) {
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('error', function (err) {
|
||||
socket.on('error', err => {
|
||||
socket = null;
|
||||
if (err && err.message.indexOf('RSV2 and RSV3 must be clear') !== -1) {
|
||||
// ignore deflate error
|
||||
@@ -173,12 +172,12 @@ function HASS(options, log) {
|
||||
log.error(err);
|
||||
}
|
||||
});
|
||||
socket.on('open', function () {
|
||||
socket.on('open', () => {
|
||||
if (!connected) {
|
||||
|
||||
}
|
||||
});
|
||||
socket.on('close', function () {
|
||||
socket.on('close', () => {
|
||||
that.socket = null;
|
||||
if (connected) {
|
||||
connected = false;
|
||||
@@ -186,7 +185,7 @@ function HASS(options, log) {
|
||||
|
||||
}
|
||||
if (!connectTimeout) {
|
||||
setTimeout(function () {
|
||||
setTimeout(() => {
|
||||
connectTimeout = null;
|
||||
that.connect();
|
||||
}, 3000);
|
||||
@@ -194,15 +193,11 @@ function HASS(options, log) {
|
||||
});
|
||||
}
|
||||
|
||||
this.isConnected = function () {
|
||||
return connected;
|
||||
};
|
||||
this.isConnected = () => connected;
|
||||
|
||||
this.getConfig = function (callback) {
|
||||
if (!connected) {
|
||||
if (typeof callback === 'function') {
|
||||
callback('not connected');
|
||||
}
|
||||
typeof callback === 'function' && callback('not connected');
|
||||
} else {
|
||||
getConfig(this.socket, callback);
|
||||
}
|
||||
@@ -210,9 +205,7 @@ function HASS(options, log) {
|
||||
|
||||
this.getStates = function (callback) {
|
||||
if (!connected) {
|
||||
if (typeof callback === 'function') {
|
||||
callback('not connected');
|
||||
}
|
||||
typeof callback === 'function' && callback('not connected');
|
||||
} else {
|
||||
getStates(this.socket, callback);
|
||||
}
|
||||
@@ -220,9 +213,7 @@ function HASS(options, log) {
|
||||
|
||||
this.getServices = function (callback) {
|
||||
if (!connected) {
|
||||
if (typeof callback === 'function') {
|
||||
callback('not connected');
|
||||
}
|
||||
typeof callback === 'function' && callback('not connected');
|
||||
} else {
|
||||
getServices(this.socket, callback);
|
||||
}
|
||||
@@ -230,9 +221,7 @@ function HASS(options, log) {
|
||||
|
||||
this.getPanels = function (callback) {
|
||||
if (!connected) {
|
||||
if (typeof callback === 'function') {
|
||||
callback('not connected');
|
||||
}
|
||||
typeof callback === 'function' && callback('not connected');
|
||||
} else {
|
||||
getPanels(this.socket, callback);
|
||||
}
|
||||
@@ -240,9 +229,7 @@ function HASS(options, log) {
|
||||
|
||||
this.callService = function (service, domain, serviceData, callback) {
|
||||
if (!connected) {
|
||||
if (typeof callback === 'function') {
|
||||
callback('not connected');
|
||||
}
|
||||
typeof callback === 'function' && callback('not connected');
|
||||
} else {
|
||||
callService(this.socket, service, domain, serviceData, callback);
|
||||
}
|
||||
@@ -254,7 +241,7 @@ function HASS(options, log) {
|
||||
connectTimeout = null;
|
||||
}
|
||||
|
||||
this.socket = new WebSocket('ws' + (options.secure ? 's' : '') + '://' + options.host + ':' + options.port + '/api/websocket', {
|
||||
this.socket = new WebSocket(`ws${options.secure ? 's' : ''}://${options.host}:${options.port}/api/websocket`, {
|
||||
perMessageDeflate: false
|
||||
});
|
||||
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
var controllerDir;
|
||||
var appName;
|
||||
|
||||
function getAppName() {
|
||||
var parts = __dirname.replace(/\\/g, '/').split('/');
|
||||
return parts[parts.length - 2].split('.')[0];
|
||||
}
|
||||
|
||||
// Get js-controller directory to load libs
|
||||
function getControllerDir(isInstall) {
|
||||
var fs = require('fs');
|
||||
// Find the js-controller location
|
||||
var controllerDir = __dirname.replace(/\\/g, '/');
|
||||
controllerDir = controllerDir.split('/');
|
||||
if (controllerDir[controllerDir.length - 3] === 'adapter') {
|
||||
controllerDir.splice(controllerDir.length - 3, 3);
|
||||
controllerDir = controllerDir.join('/');
|
||||
} else if (controllerDir[controllerDir.length - 3] === 'node_modules') {
|
||||
controllerDir.splice(controllerDir.length - 3, 3);
|
||||
controllerDir = controllerDir.join('/');
|
||||
if (fs.existsSync(controllerDir + '/node_modules/' + appName + '.js-controller')) {
|
||||
controllerDir += '/node_modules/' + appName + '.js-controller';
|
||||
} else if (fs.existsSync(controllerDir + '/node_modules/' + appName.toLowerCase() + '.js-controller')) {
|
||||
controllerDir += '/node_modules/' + appName.toLowerCase() + '.js-controller';
|
||||
} else if (!fs.existsSync(controllerDir + '/controller.js')) {
|
||||
if (!isInstall) {
|
||||
console.log('Cannot find js-controller');
|
||||
process.exit(10);
|
||||
} else {
|
||||
process.exit();
|
||||
}
|
||||
}
|
||||
} else if (fs.existsSync(__dirname + '/../../node_modules/' + appName.toLowerCase() + '.js-controller')) {
|
||||
controllerDir.splice(controllerDir.length - 2, 2);
|
||||
return controllerDir.join('/') + '/node_modules/' + appName.toLowerCase() + '.js-controller';
|
||||
} else {
|
||||
if (!isInstall) {
|
||||
console.log('Cannot find js-controller');
|
||||
process.exit(10);
|
||||
} else {
|
||||
process.exit();
|
||||
}
|
||||
}
|
||||
return controllerDir;
|
||||
}
|
||||
|
||||
// Read controller configuration file
|
||||
function getConfig() {
|
||||
var fs = require('fs');
|
||||
if (fs.existsSync(controllerDir + '/conf/' + appName + '.json')) {
|
||||
return JSON.parse(fs.readFileSync(controllerDir + '/conf/' + appName + '.json'));
|
||||
} else if (fs.existsSync(controllerDir + '/conf/' + appName.toLowerCase() + '.json')) {
|
||||
return JSON.parse(fs.readFileSync(controllerDir + '/conf/' + appName.toLowerCase() + '.json'));
|
||||
} else {
|
||||
throw new Error('Cannot find ' + controllerDir + '/conf/' + appName + '.json');
|
||||
}
|
||||
}
|
||||
appName = getAppName();
|
||||
controllerDir = getControllerDir(typeof process !== 'undefined' && process.argv && process.argv.indexOf('--install') !== -1);
|
||||
|
||||
exports.controllerDir = controllerDir;
|
||||
exports.getConfig = getConfig;
|
||||
exports.Adapter = require(controllerDir + '/lib/adapter.js');
|
||||
exports.appName = appName;
|
||||
@@ -1,25 +1,29 @@
|
||||
/* jshint -W097 */
|
||||
/* jshint strict:false */
|
||||
/* jshint strict: false */
|
||||
/* jslint node: true */
|
||||
|
||||
'use strict';
|
||||
|
||||
var utils = require(__dirname + '/lib/utils');
|
||||
var HASS = require(__dirname + '/lib/hass');
|
||||
const utils = require('@iobroker/adapter-core');
|
||||
const HASS = require('./lib/hass');
|
||||
const adapterName = require('./package.json').name.split('.').pop();
|
||||
|
||||
var adapter = utils.Adapter('hass');
|
||||
let connected = false;
|
||||
let hass;
|
||||
let adapter;
|
||||
const hassObjects = {};
|
||||
|
||||
var connected = false;
|
||||
var hass;
|
||||
var hassObjects = {};
|
||||
function startAdapter(options) {
|
||||
options = options || {};
|
||||
Object.assign(options, {name: adapterName, unload: stop});
|
||||
adapter = new utils.Adapter(options);
|
||||
|
||||
// is called if a subscribed state changes
|
||||
adapter.on('stateChange', function (id, state) {
|
||||
// is called if a subscribed state changes
|
||||
adapter.on('stateChange', (id, state) => {
|
||||
// you can use the ack flag to detect if it is status (true) or command (false)
|
||||
if (state && !state.ack) {
|
||||
if (!connected) {
|
||||
adapter.log.warn('Cannot send command to "' + id + '", because not connected');
|
||||
return;
|
||||
return adapter.log.warn('Cannot send command to "' + id + '", because not connected');
|
||||
}
|
||||
/*if (id === adapter.namespace + '.' + '.info.resync') {
|
||||
queue.push({command: 'resync'});
|
||||
@@ -29,11 +33,13 @@ adapter.on('stateChange', function (id, state) {
|
||||
if (!hassObjects[id].common.write) {
|
||||
adapter.log.warn('Object ' + id + ' is not writable!');
|
||||
} else {
|
||||
var serviceData = {};
|
||||
var fields = hassObjects[id].native.fields;
|
||||
const serviceData = {};
|
||||
const fields = hassObjects[id].native.fields;
|
||||
|
||||
for (var field in fields) {
|
||||
if (!fields.hasOwnProperty(field)) continue;
|
||||
for (const field in fields) {
|
||||
if (!fields.hasOwnProperty(field)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (field === 'entity_id') {
|
||||
serviceData.entity_id = hassObjects[id].native.entity_id
|
||||
@@ -42,32 +48,19 @@ adapter.on('stateChange', function (id, state) {
|
||||
}
|
||||
}
|
||||
|
||||
hass.callService(hassObjects[id].native.attr, hassObjects[id].native.domain || hassObjects[id].native.type, serviceData, function (err) {
|
||||
if (err) {
|
||||
adapter.log.error('Cannot control ' + id + ': ' + err);
|
||||
hass.callService(hassObjects[id].native.attr, hassObjects[id].native.domain || hassObjects[id].native.type, serviceData, err =>
|
||||
err && adapter.log.error('Cannot control ' + id + ': ' + err));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Some message was sent to adapter instance over message box. Used by email, pushover, text2speech, ...
|
||||
adapter.on('message', function (obj) {
|
||||
if (typeof obj === 'object' && obj.message) {
|
||||
if (obj.command === 'send') {
|
||||
// e.g. send email or pushover or whatever
|
||||
console.log('send command');
|
||||
// is called when databases are connected and adapter received configuration.
|
||||
// start here!
|
||||
adapter.on('ready', main);
|
||||
|
||||
// Send response in callback if required
|
||||
if (obj.callback) adapter.sendTo(obj.from, obj.command, 'Message received', obj.callback);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// is called when databases are connected and adapter received configuration.
|
||||
// start here!
|
||||
adapter.on('ready', main);
|
||||
return adapter;
|
||||
}
|
||||
|
||||
function getUnit(name) {
|
||||
name = name.toLowerCase();
|
||||
@@ -87,37 +80,34 @@ function getUnit(name) {
|
||||
|
||||
function syncStates(states, cb) {
|
||||
if (!states || !states.length) {
|
||||
cb();
|
||||
return;
|
||||
return cb();
|
||||
}
|
||||
var state = states.shift();
|
||||
var id = state.id;
|
||||
const state = states.shift();
|
||||
const id = state.id;
|
||||
delete state.id;
|
||||
|
||||
adapter.setForeignState(id, state, function (err) {
|
||||
if (err) adapter.log.error(err);
|
||||
adapter.setForeignState(id, state, err => {
|
||||
err && adapter.log.error(err);
|
||||
setImmediate(syncStates, states, cb);
|
||||
});
|
||||
}
|
||||
|
||||
function syncObjects(objects, cb) {
|
||||
if (!objects || !objects.length) {
|
||||
cb();
|
||||
return;
|
||||
return cb();
|
||||
}
|
||||
var obj = objects.shift();
|
||||
const obj = objects.shift();
|
||||
hassObjects[obj._id] = obj;
|
||||
|
||||
adapter.getForeignObject(obj._id, function (err, oldObj) {
|
||||
adapter.getForeignObject(obj._id, (err, oldObj) => {
|
||||
|
||||
if (err) adapter.log.error(err);
|
||||
err && adapter.log.error(err);
|
||||
|
||||
if (!oldObj) {
|
||||
adapter.log.debug('Create "' + obj._id + '"');
|
||||
hassObjects[obj._id] = obj;
|
||||
adapter.setForeignObject(obj._id, obj, function (err) {
|
||||
if (err) adapter.log.error(err);
|
||||
|
||||
adapter.setForeignObject(obj._id, obj, err => {
|
||||
err && adapter.log.error(err);
|
||||
setImmediate(syncObjects, objects, cb);
|
||||
});
|
||||
} else {
|
||||
@@ -126,8 +116,8 @@ function syncObjects(objects, cb) {
|
||||
oldObj.native = obj.native;
|
||||
|
||||
adapter.log.debug('Update "' + obj._id + '"');
|
||||
adapter.setForeignObject(obj._id, oldObj, function (err) {
|
||||
if (err) adapter.log.error(err);
|
||||
adapter.setForeignObject(obj._id, oldObj, err => {
|
||||
err => adapter.log.error(err);
|
||||
setImmediate(syncObjects, objects, cb);
|
||||
});
|
||||
} else {
|
||||
@@ -138,7 +128,7 @@ function syncObjects(objects, cb) {
|
||||
}
|
||||
|
||||
function syncRoom(room, members, cb) {
|
||||
adapter.getForeignObject('enum.rooms.' + room, function (err, obj) {
|
||||
adapter.getForeignObject('enum.rooms.' + room, (err, obj) => {
|
||||
if (!obj) {
|
||||
obj = {
|
||||
_id: 'enum.rooms.' + room,
|
||||
@@ -150,15 +140,15 @@ function syncRoom(room, members, cb) {
|
||||
native: {}
|
||||
};
|
||||
adapter.log.debug('Update "' + obj._id + '"');
|
||||
adapter.setForeignObject(obj._id, obj, function (err) {
|
||||
if (err) adapter.log.error(err);
|
||||
adapter.setForeignObject(obj._id, obj, err => {
|
||||
err && adapter.log.error(err);
|
||||
cb();
|
||||
});
|
||||
} else {
|
||||
obj.common = obj.common || {};
|
||||
obj.common.members = obj.common.members || [];
|
||||
var changed = false;
|
||||
for (var m = 0; m < members.length; m++) {
|
||||
let changed = false;
|
||||
for (let m = 0; m < members.length; m++) {
|
||||
if (obj.common.members.indexOf(members[m]) === -1) {
|
||||
changed = true;
|
||||
obj.common.members.push(members[m]);
|
||||
@@ -166,8 +156,8 @@ function syncRoom(room, members, cb) {
|
||||
}
|
||||
if (changed) {
|
||||
adapter.log.debug('Update "' + obj._id + '"');
|
||||
adapter.setForeignObject(obj._id, obj, function (err) {
|
||||
if (err) adapter.log.error(err);
|
||||
adapter.setForeignObject(obj._id, obj, err => {
|
||||
err && adapter.log.error(err);
|
||||
cb();
|
||||
});
|
||||
} else {
|
||||
@@ -177,41 +167,41 @@ function syncRoom(room, members, cb) {
|
||||
});
|
||||
}
|
||||
|
||||
var knownAttributes = {
|
||||
const knownAttributes = {
|
||||
azimuth: {write: false, read: true, unit: '°'},
|
||||
elevation: {write: false, read: true, unit: '°'}
|
||||
};
|
||||
|
||||
|
||||
var ERRORS = {
|
||||
const ERRORS = {
|
||||
1: 'ERR_CANNOT_CONNECT',
|
||||
2: 'ERR_INVALID_AUTH',
|
||||
3: 'ERR_CONNECTION_LOST'
|
||||
};
|
||||
var mapTypes = {
|
||||
const mapTypes = {
|
||||
'string': 'string',
|
||||
'number': 'number',
|
||||
'object': 'mixed',
|
||||
'boolean': 'boolean'
|
||||
};
|
||||
var skipServices = [
|
||||
const skipServices = [
|
||||
'persistent_notification'
|
||||
];
|
||||
|
||||
function parseStates(entities, services, callback) {
|
||||
var objs = [];
|
||||
var states = [];
|
||||
var obj;
|
||||
var channel;
|
||||
for (var e = 0; e < entities.length; e++) {
|
||||
var entity = entities[e];
|
||||
const objs = [];
|
||||
const states = [];
|
||||
let obj;
|
||||
let channel;
|
||||
for (let e = 0; e < entities.length; e++) {
|
||||
const entity = entities[e];
|
||||
if (!entity) continue;
|
||||
|
||||
var name = entity.name || (entity.attributes && entity.attributes.friendly_name ? entity.attributes.friendly_name : entity.entity_id);
|
||||
var desc = entity.attributes && entity.attributes.attribution ? entity.attributes.attribution : undefined;
|
||||
const name = entity.name || (entity.attributes && entity.attributes.friendly_name ? entity.attributes.friendly_name : entity.entity_id);
|
||||
const desc = entity.attributes && entity.attributes.attribution ? entity.attributes.attribution : undefined;
|
||||
|
||||
channel = {
|
||||
_id: adapter.namespace + '.entities.' + entity.entity_id,
|
||||
_id: `${adapter.namespace}.entities.${entity.entity_id}`,
|
||||
common: {
|
||||
name: name
|
||||
},
|
||||
@@ -224,15 +214,15 @@ function parseStates(entities, services, callback) {
|
||||
if (desc) channel.common.desc = desc;
|
||||
objs.push(channel);
|
||||
|
||||
var lc = entity.last_changed ? new Date(entity.last_changed).getTime() : undefined;
|
||||
var ts = entity.last_updated ? new Date(entity.last_updated).getTime() : undefined;
|
||||
const lc = entity.last_changed ? new Date(entity.last_changed).getTime() : undefined;
|
||||
const ts = entity.last_updated ? new Date(entity.last_updated).getTime() : undefined;
|
||||
|
||||
if (entity.state !== undefined) {
|
||||
obj = {
|
||||
_id: adapter.namespace + '.entities.' + entity.entity_id + '.state',
|
||||
_id: `${adapter.namespace}.entities.${entity.entity_id}.state`,
|
||||
type: 'state',
|
||||
common: {
|
||||
name: name + ' STATE',
|
||||
name: `${name} STATE`,
|
||||
read: true,
|
||||
write: false
|
||||
},
|
||||
@@ -250,11 +240,13 @@ function parseStates(entities, services, callback) {
|
||||
}
|
||||
|
||||
if (entity.attributes) {
|
||||
for (var attr in entity.attributes) {
|
||||
for (const attr in entity.attributes) {
|
||||
if (entity.attributes.hasOwnProperty(attr)) {
|
||||
if (attr === 'friendly_name' || attr === 'unit_of_measurement' || attr === 'icon') continue;
|
||||
if (attr === 'friendly_name' || attr === 'unit_of_measurement' || attr === 'icon') {
|
||||
continue;
|
||||
}
|
||||
|
||||
var common;
|
||||
let common;
|
||||
if (knownAttributes[attr]) {
|
||||
common = Object.assign({}, knownAttributes[attr]);
|
||||
} else {
|
||||
@@ -262,7 +254,7 @@ function parseStates(entities, services, callback) {
|
||||
}
|
||||
|
||||
obj = {
|
||||
_id: adapter.namespace + '.entities.' + entity.entity_id + '.' + attr,
|
||||
_id: `${adapter.namespace}.entities.${entity.entity_id}.${attr}`,
|
||||
type: 'state',
|
||||
common: common,
|
||||
native: {
|
||||
@@ -291,14 +283,14 @@ function parseStates(entities, services, callback) {
|
||||
}
|
||||
}
|
||||
|
||||
var serviceType = entity.entity_id.split('.')[0];
|
||||
const serviceType = entity.entity_id.split('.')[0];
|
||||
|
||||
if (services[serviceType] && skipServices.indexOf(serviceType) === -1) {
|
||||
var service = services[serviceType];
|
||||
for (var s in service) {
|
||||
if (services[serviceType] && !skipServices.includes(serviceType)) {
|
||||
const service = services[serviceType];
|
||||
for (const s in service) {
|
||||
if (service.hasOwnProperty(s)) {
|
||||
obj = {
|
||||
_id: adapter.namespace + '.entities.' + entity.entity_id + '.' + s,
|
||||
_id: `${adapter.namespace}.entities.${entity.entity_id}.${s}`,
|
||||
type: 'state',
|
||||
common: {
|
||||
desc: service[s].description,
|
||||
@@ -320,9 +312,8 @@ function parseStates(entities, services, callback) {
|
||||
}
|
||||
}
|
||||
|
||||
syncObjects(objs, function () {
|
||||
syncStates(states, callback);
|
||||
});
|
||||
syncObjects(objs, () =>
|
||||
syncStates(states, callback));
|
||||
}
|
||||
|
||||
function main() {
|
||||
@@ -336,60 +327,60 @@ function main() {
|
||||
|
||||
hass = new HASS(adapter.config, adapter.log);
|
||||
|
||||
hass.on('error', function (err) {
|
||||
adapter.log.error(err);
|
||||
});
|
||||
hass.on('state_changed', function (entity) {
|
||||
var id = adapter.namespace + '.entities.' + entity.entity_id + '.';
|
||||
var lc = entity.last_changed ? new Date(entity.last_changed).getTime() : undefined;
|
||||
var ts = entity.last_updated ? new Date(entity.last_updated).getTime() : undefined;
|
||||
hass.on('error', err =>
|
||||
adapter.log.error(err));
|
||||
|
||||
hass.on('state_changed', entity => {
|
||||
const id = adapter.namespace + '.entities.' + entity.entity_id + '.';
|
||||
const lc = entity.last_changed ? new Date(entity.last_changed).getTime() : undefined;
|
||||
const ts = entity.last_updated ? new Date(entity.last_updated).getTime() : undefined;
|
||||
if (entity.state !== undefined) {
|
||||
adapter.setForeignState(id + 'state', {val: entity.state, ack: true, lc: lc, ts: ts});
|
||||
}
|
||||
if (entity.attributes) {
|
||||
for (var attr in entity.attributes) {
|
||||
if (!entity.attributes.hasOwnProperty(attr) || attr === 'friendly_name' || attr === 'unit_of_measurement' || attr === 'icon') continue;
|
||||
for (const attr in entity.attributes) {
|
||||
if (!entity.attributes.hasOwnProperty(attr) || attr === 'friendly_name' || attr === 'unit_of_measurement' || attr === 'icon') {
|
||||
continue;
|
||||
}
|
||||
adapter.setForeignState(id + attr, {val: entity.attributes[attr], ack: true, lc: lc, ts: ts});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
hass.on('connected', function () {
|
||||
hass.on('connected', () => {
|
||||
if (!connected) {
|
||||
adapter.log.debug('Connected');
|
||||
connected = true;
|
||||
adapter.setState('info.connection', true, true);
|
||||
hass.getConfig(function (err, config) {
|
||||
hass.getConfig((err, config) => {
|
||||
if (err) {
|
||||
adapter.log.error('Cannot read config: ' + err);
|
||||
return;
|
||||
}
|
||||
//adapter.log.debug(JSON.stringify(config));
|
||||
setTimeout(function () {
|
||||
hass.getStates(function (err, states) {
|
||||
setTimeout(() =>
|
||||
hass.getStates((err, states) => {
|
||||
if (err) {
|
||||
return adapter.log.error('Cannot read states: ' + err);
|
||||
}
|
||||
//adapter.log.debug(JSON.stringify(states));
|
||||
setTimeout(function () {
|
||||
hass.getServices(function (err, services) {
|
||||
setTimeout(() =>
|
||||
hass.getServices((err, services) => {
|
||||
if (err) {
|
||||
adapter.log.error('Cannot read states: ' + err);
|
||||
} else {
|
||||
//adapter.log.debug(JSON.stringify(services));
|
||||
parseStates(states, services, function () {
|
||||
parseStates(states, services, () => {
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
}), 100);
|
||||
}), 100);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
hass.on('disconnected', function () {
|
||||
hass.on('disconnected', () => {
|
||||
if (connected) {
|
||||
adapter.log.debug('Disconnected');
|
||||
connected = false;
|
||||
@@ -399,3 +390,11 @@ function main() {
|
||||
|
||||
hass.connect();
|
||||
}
|
||||
|
||||
// If started as allInOne/compact mode => return function to create instance
|
||||
if (module && module.parent) {
|
||||
module.exports = startAdapter;
|
||||
} else {
|
||||
// or start the instance directly
|
||||
startAdapter();
|
||||
}
|
||||
|
||||
+10
-7
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "iobroker.hass",
|
||||
"version": "0.1.0",
|
||||
"version": "1.0.0",
|
||||
"description": "Home Assistant",
|
||||
"author": {
|
||||
"name": "bluefox",
|
||||
@@ -26,17 +26,20 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"home-assistant-js-websocket": "^1.1.4",
|
||||
"websocket": "^1.0.25",
|
||||
"ws": "^5.0.0"
|
||||
"websocket": "^1.0.33",
|
||||
"ws": "^5.0.0",
|
||||
"@iobroker/adapter-core": "^2.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"gulp": "^3.9.1",
|
||||
"mocha": "^4.1.0",
|
||||
"chai": "^4.1.2"
|
||||
"@alcalzone/release-script": "^1.8.1",
|
||||
"gulp": "^4.0.2",
|
||||
"mocha": "^8.2.1",
|
||||
"chai": "^4.2.0"
|
||||
},
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"test": "node node_modules/mocha/bin/mocha --exit"
|
||||
"test": "node node_modules/mocha/bin/mocha --exit",
|
||||
"release": "node node_modules/@alcalzone/release-script/bin/release.js"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/ioBroker/ioBroker.hass/issues"
|
||||
|
||||
Reference in New Issue
Block a user