Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a4a7abedbe | ||
|
|
9ab4db078f | ||
|
|
2ec6bf8150 | ||
|
|
0dd97e69c8 | ||
|
|
8ff8341088 | ||
|
|
0cb8ed8a13 | ||
|
|
46d58e00e3 | ||
|
|
0fa719edd0 | ||
|
|
5cb493481e | ||
|
|
0d28c7e54b | ||
|
|
d89288a0b8 | ||
|
|
f03bf3d9a6 | ||
|
|
3b83e686f7 | ||
|
|
b887a75ede | ||
|
|
96bc8592b3 | ||
|
|
4d939862d6 | ||
|
|
d297bf3d27 | ||
|
|
ba6f42601a | ||
|
|
46eebb0a82 | ||
|
|
3ffe4fe555 | ||
|
|
50962fb833 | ||
|
|
aa7a06d750 | ||
|
|
7c966c5bd9 | ||
|
|
1f1fc7ef43 | ||
|
|
4e19c7e334 | ||
|
|
84dee7cd6a | ||
|
|
5d8816f464 | ||
|
|
f1376e5e5b | ||
|
|
d042d65588 | ||
|
|
088113848d | ||
|
|
c8be38859d | ||
|
|
fd5517c976 | ||
|
|
aedde9a4b9 | ||
|
|
a148fa4e33 | ||
|
|
1451e497d8 | ||
|
|
85ef3afc04 | ||
|
|
a68f254e60 | ||
|
|
a75fbf84bb | ||
|
|
66953a6e0d |
@@ -28,9 +28,9 @@ jobs:
|
|||||||
node-version: [12.x]
|
node-version: [12.x]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v2
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v2.4.0
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
|
|
||||||
@@ -60,9 +60,9 @@ jobs:
|
|||||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v2
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v2.4.0
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ jobs:
|
|||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v2.4.0
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
|
|
||||||
@@ -140,19 +140,17 @@ jobs:
|
|||||||
prerelease: ${{ contains(steps.extract_release.outputs.VERSION, '-') }}
|
prerelease: ${{ contains(steps.extract_release.outputs.VERSION, '-') }}
|
||||||
body: ${{ steps.extract_release.outputs.BODY }}
|
body: ${{ steps.extract_release.outputs.BODY }}
|
||||||
|
|
||||||
#- name: Notify Sentry.io about the release
|
- name: Notify Sentry.io about the release
|
||||||
# run: |
|
run: |
|
||||||
# npm i -g @sentry/cli
|
npm i -g @sentry/cli
|
||||||
# export SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}
|
export SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||||
# export SENTRY_URL=https://sentry.iobroker.net
|
export SENTRY_URL=https://sentry.iobroker.net
|
||||||
# export SENTRY_ORG=iobroker
|
export SENTRY_ORG=iobroker
|
||||||
# export SENTRY_PROJECT=iobroker-hass
|
export SENTRY_PROJECT=iobroker-hass
|
||||||
# export SENTRY_VERSION=iobroker.hass@${{ steps.extract_release.outputs.VERSION }}
|
export SENTRY_VERSION=iobroker.hass@${{ steps.extract_release.outputs.VERSION }}
|
||||||
# sentry-cli releases new $SENTRY_VERSION
|
sentry-cli releases new $SENTRY_VERSION
|
||||||
# sentry-cli releases finalize $SENTRY_VERSION
|
sentry-cli releases set-commits $SENTRY_VERSION --auto
|
||||||
|
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
|
# Add the following line BEFORE finalize if sourcemap uploads are needed
|
||||||
# sentry-cli releases files $SENTRY_VERSION upload-sourcemaps build/
|
# sentry-cli releases files $SENTRY_VERSION upload-sourcemaps build/
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"require": [
|
||||||
|
"./test/mocha.setup.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"plugins": ["iobroker", "license"]
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2018-2020 bluefox <dogafox@gmail.com>
|
Copyright (c) 2018-2022 bluefox <dogafox@gmail.com>
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
@@ -1,15 +1,85 @@
|
|||||||

|

|
||||||
# ioBroker.hass
|
# ioBroker.hass
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
[](https://www.npmjs.com/package/iobroker.hass)
|
[](https://www.npmjs.com/package/iobroker.hass)
|
||||||
|
|
||||||
|

|
||||||
|
[](https://weblate.iobroker.net/engage/adapters/?utm_source=widget)
|
||||||
[](https://www.npmjs.com/package/iobroker.hass)
|
[](https://www.npmjs.com/package/iobroker.hass)
|
||||||
|
|
||||||
|
**This adapter uses Sentry libraries to automatically report exceptions and code errors to the developers.** For more details and for information how to disable the error reporting see [Sentry-Plugin Documentation](https://github.com/ioBroker/plugin-sentry#plugin-sentry)! Sentry reporting is used starting with js-controller 3.0.
|
||||||
|
|
||||||
|
|
||||||
This adapter allows the connecting of Home Assistant to ioBroker.
|
This adapter allows the connecting of Home Assistant to ioBroker.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
Create a long term token in HASS and use it as PW (copy it also in the repeat field).
|
Create a long term token in HASS and use it as PW (copy it also in the repeat field).
|
||||||
|
|
||||||
|
Then it should read out all attributes for all devices. Services might be controllable (e.g. "turn_on"). To control services you have two options:
|
||||||
|
* Set the state with an ack=false value which is not a string (e.g. Boolean true) then it will be triggered also in HASS without additional service data
|
||||||
|
* Set the state with an ack=false String value which is a stringified JSON object to call the service and use the JSON object as service data
|
||||||
|
|
||||||
|
For the last option on a light.turn_off with e.g. `{"transition":10,"flash":"short"}` these two service data details are sent with the call to HASS. The available fields with their data definition can be seen in the JSON definition of the ioBroker object in the native.fields section and would look like the following in the above example:
|
||||||
|
|
||||||
|
`
|
||||||
|
...
|
||||||
|
native: {
|
||||||
|
"fields": {
|
||||||
|
"transition": {
|
||||||
|
"name": "Transition",
|
||||||
|
"description": "Duration it takes to get to next state.",
|
||||||
|
"selector": {
|
||||||
|
"number": {
|
||||||
|
"min": 0,
|
||||||
|
"max": 300,
|
||||||
|
"unit_of_measurement": "seconds"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flash": {
|
||||||
|
"name": "Flash",
|
||||||
|
"description": "If the light should flash.",
|
||||||
|
"advanced": true,
|
||||||
|
"selector": {
|
||||||
|
"select": {
|
||||||
|
"options": [
|
||||||
|
"long",
|
||||||
|
"short"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"entity_id": "light.mi_control_hub_light",
|
||||||
|
"attr": "turn_off",
|
||||||
|
"type": "light"
|
||||||
|
}
|
||||||
|
...
|
||||||
|
`
|
||||||
|
|
||||||
|
For some services like set_speed it is required to call with a JSON object like `{speed: "high"}` in general to provide required values. In this case the field definition look e.g. like:
|
||||||
|
|
||||||
|
```
|
||||||
|
...
|
||||||
|
native: {
|
||||||
|
"fields": {
|
||||||
|
"speed": {
|
||||||
|
"name": "Speed",
|
||||||
|
"description": "Speed setting.",
|
||||||
|
"required": true,
|
||||||
|
"example": "low",
|
||||||
|
"selector": {
|
||||||
|
"text": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
...
|
||||||
|
}
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
There is a good article about connection.
|
There is a good article about connection.
|
||||||
|
|
||||||
@@ -23,6 +93,11 @@ Please check it https://www.smarthomejetzt.de/mit-iobroker-auf-eine-home-assista
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
### 1.1.0 (2022-03-24)
|
||||||
|
* IMPORTANT: You need to re-enter the password once after installing this version!
|
||||||
|
* (Apollon77) Implement Service triggers to use any value to trigger or stringified JSON to call with fields
|
||||||
|
* (Apollon77) Optimize unload handling
|
||||||
|
* (Apollon7) Add Sentry for crash reporting
|
||||||
|
|
||||||
### 1.0.1 (2021-09-04)
|
### 1.0.1 (2021-09-04)
|
||||||
* IMPORTANT: js-controller 2.0 is needed st least!
|
* IMPORTANT: js-controller 2.0 is needed st least!
|
||||||
@@ -38,7 +113,7 @@ Please check it https://www.smarthomejetzt.de/mit-iobroker-auf-eine-home-assista
|
|||||||
## License
|
## License
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2018-2020 bluefox <dogafox@gmail.com>
|
Copyright (c) 2018-2022 bluefox <dogafox@gmail.com>
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"Home assistant IP:": "IP-Adresse des Heimassistenten:",
|
||||||
|
"Home assistant WS Port:": "Home Assistant WS-Port:",
|
||||||
|
"Password repeat:": "Passwort wiederholen:",
|
||||||
|
"Password:": "Passwort:",
|
||||||
|
"Passwords missmatch!": "Passwörter stimmen nicht überein!",
|
||||||
|
"Secure:": "HTTPS?"
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"Home assistant IP:": "Home assistant IP:",
|
||||||
|
"Home assistant WS Port:": "Home assistant WS Port:",
|
||||||
|
"Password repeat:": "Password repeat:",
|
||||||
|
"Password:": "Password:",
|
||||||
|
"Passwords missmatch!": "Passwords missmatch!",
|
||||||
|
"Secure:": "HTTPS?"
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"Home assistant IP:": "IP del asistente de hogar:",
|
||||||
|
"Home assistant WS Port:": "Asistente doméstico Puerto WS:",
|
||||||
|
"Password repeat:": "Repite la contraseña:",
|
||||||
|
"Password:": "Clave:",
|
||||||
|
"Passwords missmatch!": "¡Las contraseñas no coinciden!",
|
||||||
|
"Secure:": "¿HTTPS?:"
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"Home assistant IP:": "IP de l'assistant à domicile :",
|
||||||
|
"Home assistant WS Port:": "Port WS de l'assistant domestique :",
|
||||||
|
"Password repeat:": "Répéter le mot de passe :",
|
||||||
|
"Password:": "Mot de passe:",
|
||||||
|
"Passwords missmatch!": "Les mots de passe ne correspondent pas !",
|
||||||
|
"Secure:": "HTTPS ?"
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"Home assistant IP:": "IP assistente domestico:",
|
||||||
|
"Home assistant WS Port:": "Porta WS dell'assistente domestico:",
|
||||||
|
"Password repeat:": "Ripeti password:",
|
||||||
|
"Password:": "Parola d'ordine:",
|
||||||
|
"Passwords missmatch!": "Le password non corrispondono!",
|
||||||
|
"Secure:": "HTTPS?"
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"Home assistant IP:": "Thuisassistent IP:",
|
||||||
|
"Home assistant WS Port:": "Thuisassistent WS Poort:",
|
||||||
|
"Password repeat:": "Wachtwoord herhalen:",
|
||||||
|
"Password:": "Wachtwoord:",
|
||||||
|
"Passwords missmatch!": "Wachtwoorden komen niet overeen!",
|
||||||
|
"Secure:": "HTTPS?"
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"Home assistant IP:": "Adres IP asystenta domowego:",
|
||||||
|
"Home assistant WS Port:": "Asystent domowy Port WS:",
|
||||||
|
"Password repeat:": "Powtórz hasło:",
|
||||||
|
"Password:": "Hasło:",
|
||||||
|
"Passwords missmatch!": "Niezgodność haseł!",
|
||||||
|
"Secure:": "HTTPS?"
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"Home assistant IP:": "IP do assistente doméstico:",
|
||||||
|
"Home assistant WS Port:": "Assistente doméstico Porta WS:",
|
||||||
|
"Password repeat:": "Repetição de senha:",
|
||||||
|
"Password:": "Senha:",
|
||||||
|
"Passwords missmatch!": "As senhas não correspondem!",
|
||||||
|
"Secure:": "HTTPS?"
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"Home assistant IP:": "Домашний помощник IP:",
|
||||||
|
"Home assistant WS Port:": "Домашний помощник WS Порт:",
|
||||||
|
"Password repeat:": "Повтор пароля:",
|
||||||
|
"Password:": "Пароль:",
|
||||||
|
"Passwords missmatch!": "Пароли не совпадают!",
|
||||||
|
"Secure:": "HTTPS?"
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"Home assistant IP:": "家庭助理IP:",
|
||||||
|
"Home assistant WS Port:": "家庭助理 WS 端口:",
|
||||||
|
"Password repeat:": "密码重复:",
|
||||||
|
"Password:": "密码:",
|
||||||
|
"Passwords missmatch!": "密码不匹配!",
|
||||||
|
"Secure:": "HTTPS?"
|
||||||
|
}
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<link rel="stylesheet" type="text/css" href="../../lib/css/themes/jquery-ui/redmond/jquery-ui.min.css"/>
|
|
||||||
<link rel="stylesheet" type="text/css" href="../../css/adapter.css"/>
|
|
||||||
|
|
||||||
<script type="text/javascript" src="../../lib/js/jquery-1.11.1.min.js"></script>
|
|
||||||
<script type="text/javascript" src="../../socket.io/socket.io.js"></script>
|
|
||||||
<script type="text/javascript" src="../../lib/js/jquery-ui-1.10.3.full.min.js"></script>
|
|
||||||
<script type="text/javascript" src="../../js/translate.js"></script>
|
|
||||||
<script type="text/javascript" src="../../js/adapter-settings.js"></script>
|
|
||||||
<script type="text/javascript" src="words.js"></script>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
|
|
||||||
function load(settings, onChange) {
|
|
||||||
if (!settings) return;
|
|
||||||
|
|
||||||
if (settings.password === undefined) settings.password = '';
|
|
||||||
if (settings.prompt === undefined) settings.prompt = 'hass>';
|
|
||||||
|
|
||||||
$('.value').each(function () {
|
|
||||||
var key = $(this).attr('id');
|
|
||||||
var $value = $('#' + key + '.value');
|
|
||||||
if ($value.attr('type') === 'checkbox') {
|
|
||||||
$value.prop('checked', settings[key]).change(function() {
|
|
||||||
onChange();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
$value.val(settings[key]).change(function() {
|
|
||||||
onChange();
|
|
||||||
}).keyup(function() {
|
|
||||||
onChange();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Signal to admin, that no changes yet
|
|
||||||
onChange(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
function save(callback) {
|
|
||||||
var obj = {};
|
|
||||||
|
|
||||||
if ($('#password').val() !== $('#passwordRepeat').val()) {
|
|
||||||
showMessage(_('Passwords missmatch!'), _('Warning'), 'alert');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$('.value').each(function () {
|
|
||||||
var $this = $(this);
|
|
||||||
if ($this.attr('type') === 'checkbox') {
|
|
||||||
obj[$this.attr('id')] = $this.prop('checked');
|
|
||||||
} else {
|
|
||||||
obj[$this.attr('id')] = $this.val();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
callback(obj);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="adapter-container">
|
|
||||||
<table><tr>
|
|
||||||
<td><img src="hass.png"/></td>
|
|
||||||
<td><h3 class="translate">FHEM adapter settings</h3></td>
|
|
||||||
</tr></table>
|
|
||||||
<table>
|
|
||||||
<tr><td><label class="translate" for="host">Home assistant IP:</label></td><td class="admin-icon"></td><td><input class="value" id="host" /></td></tr>
|
|
||||||
<tr><td><label class="translate" for="port">Home assistant WS Port:</label></td><td class="admin-icon"></td><td><input class="value" id="port" size="5" maxlength="5"/></td></tr>
|
|
||||||
<tr><td><label class="translate" for="password">Password:</label></td><td class="admin-icon"></td><td><input class="value" id="password" type="password"/></td></tr>
|
|
||||||
<tr><td><label class="translate" for="passwordRepeat">Password repeat:</label></td><td class="admin-icon"></td><td><input type="password" id="passwordRepeat"/></td></tr>
|
|
||||||
<tr><td><label class="translate" for="secure">Secure:</label></td><td class="admin-icon"></td><td><input class="value" id="secure" type="checkbox"/></td></tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
+49
-16
@@ -1,12 +1,14 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<link rel="stylesheet" type="text/css" href="../../lib/css/themes/jquery-ui/redmond/jquery-ui.min.css"/>
|
<!-- Materialze style -->
|
||||||
<link rel="stylesheet" type="text/css" href="../../css/adapter.css"/>
|
<link rel="stylesheet" type="text/css" href="../../css/adapter.css"/>
|
||||||
|
<link rel="stylesheet" type="text/css" href="../../lib/css/materialize.css">
|
||||||
|
|
||||||
<script type="text/javascript" src="../../lib/js/jquery-1.11.1.min.js"></script>
|
<script type="text/javascript" src="../../lib/js/jquery-3.2.1.min.js"></script>
|
||||||
<script type="text/javascript" src="../../socket.io/socket.io.js"></script>
|
<script type="text/javascript" src="../../socket.io/socket.io.js"></script>
|
||||||
<script type="text/javascript" src="../../lib/js/jquery-ui-1.10.3.full.min.js"></script>
|
|
||||||
<script type="text/javascript" src="../../js/translate.js"></script>
|
<script type="text/javascript" src="../../js/translate.js"></script>
|
||||||
|
<script type="text/javascript" src="../../lib/js/materialize.js"></script>
|
||||||
<script type="text/javascript" src="../../js/adapter-settings.js"></script>
|
<script type="text/javascript" src="../../js/adapter-settings.js"></script>
|
||||||
<script type="text/javascript" src="words.js"></script>
|
<script type="text/javascript" src="words.js"></script>
|
||||||
|
|
||||||
@@ -16,7 +18,7 @@
|
|||||||
if (!settings) return;
|
if (!settings) return;
|
||||||
|
|
||||||
if (settings.password === undefined) settings.password = '';
|
if (settings.password === undefined) settings.password = '';
|
||||||
if (settings.prompt === undefined) settings.prompt = 'hass>';
|
settings.passwordRepeat = settings.password;
|
||||||
|
|
||||||
$('.value').each(function () {
|
$('.value').each(function () {
|
||||||
var key = $(this).attr('id');
|
var key = $(this).attr('id');
|
||||||
@@ -53,23 +55,54 @@
|
|||||||
obj[$this.attr('id')] = $this.val();
|
obj[$this.attr('id')] = $this.val();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
delete obj.passwordRepeat;
|
||||||
|
|
||||||
callback(obj);
|
callback(obj);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="adapter-container">
|
<div class="m adapter-container">
|
||||||
<table><tr>
|
<div class="row">
|
||||||
<td><img src="hass.png" alt="logo"/></td>
|
<div class="col s12 m4 l2">
|
||||||
<td><h3 class="translate">Home assistant adapter settings</h3></td>
|
<img src="hass.png" class="logo">
|
||||||
</tr></table>
|
</div>
|
||||||
<table>
|
</div>
|
||||||
<tr><td><label class="translate" for="host">Home assistant IP:</label></td><td class="admin-icon"></td><td><input class="value" id="host" /></td></tr>
|
|
||||||
<tr><td><label class="translate" for="port">Home assistant WS Port:</label></td><td class="admin-icon"></td><td><input class="value" id="port" size="5" maxlength="5"/></td></tr>
|
<div class="row">
|
||||||
<tr><td><label class="translate" for="password">Password:</label></td><td class="admin-icon"></td><td><input class="value" id="password" type="password"/></td></tr>
|
<div class="col s12 m8 l8">
|
||||||
<tr><td><label class="translate" for="passwordRepeat">Password repeat:</label></td><td class="admin-icon"></td><td><input type="password" id="passwordRepeat"/></td></tr>
|
<div class="col s4 input-field">
|
||||||
<tr><td><label class="translate" for="secure">Secure:</label></td><td class="admin-icon"></td><td><input class="value" id="secure" type="checkbox"/></td></tr>
|
<input type="text" class="value" id="host" />
|
||||||
</table>
|
<label for="host" class="translate">Home assistant IP:</label>
|
||||||
|
</div>
|
||||||
|
<div class="col s4 input-field">
|
||||||
|
<input type="text" class="value" id="port" size="5" maxlength="5"/>
|
||||||
|
<label for="port" class="translate">Home assistant WS Port:</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col s12 m8 l8">
|
||||||
|
<div class="col s6 m4 input-field">
|
||||||
|
<input type="text" class="value" id="password" />
|
||||||
|
<label for="password" class="translate">Password:</label>
|
||||||
|
</div>
|
||||||
|
<div class="col s6 m4 input-field">
|
||||||
|
<input type="text" class="value" id="passwordRepeat" />
|
||||||
|
<label for="passwordRepeat" class="translate">Password repeat:</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col s12 m8 l8">
|
||||||
|
<div class="col s6 m4 input-field">
|
||||||
|
<input id="secure" type="checkbox" class="value" />
|
||||||
|
<span for="secure" class="translate">Secure:</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
+9
-17
@@ -1,19 +1,11 @@
|
|||||||
|
/*global systemDictionary:true */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
systemDictionary = {
|
systemDictionary = {
|
||||||
"FHEM adapter settings":{"de": "FHEM Adapter Einstellungen", "ru": "Настройки драйвера FHEM"},
|
"Home assistant IP:": { "en": "Home assistant IP:", "de": "IP-Adresse des Heimassistenten:", "ru": "Домашний помощник IP:", "pt": "IP do assistente doméstico:", "nl": "Thuisassistent IP:", "fr": "IP de l'assistant à domicile :", "it": "IP assistente domestico:", "es": "IP del asistente de hogar:", "pl": "Adres IP asystenta domowego:", "zh-cn": "家庭助理IP:"},
|
||||||
"FHEM Telnet IP:": {"de": "FHEM Telnet IP:", "ru": "FHEM Telnet IP:"},
|
"Home assistant WS Port:": { "en": "Home assistant WS Port:", "de": "Home Assistant WS-Port:", "ru": "Домашний помощник WS Порт:", "pt": "Assistente doméstico Porta WS:", "nl": "Thuisassistent WS Poort:", "fr": "Port WS de l'assistant domestique :", "it": "Porta WS dell'assistente domestico:", "es": "Asistente doméstico Puerto WS:", "pl": "Asystent domowy Port WS:", "zh-cn": "家庭助理 WS 端口:"},
|
||||||
"FHEM Telnet Port:": {"en": "FHEM Telnet Port:", "de": "FHEM Telnet Port:", "ru": "FHEM Telnet порт:"},
|
"Password repeat:": { "en": "Password repeat:", "de": "Passwort wiederholen:", "ru": "Повтор пароля:", "pt": "Repetição de senha:", "nl": "Wachtwoord herhalen:", "fr": "Répéter le mot de passe :", "it": "Ripeti password:", "es": "Repite la contraseña:", "pl": "Powtórz hasło:", "zh-cn": "密码重复:"},
|
||||||
"Password:": {"en": "Password:", "de": "Kennwort:", "ru": "Пароль:"},
|
"Password:": { "en": "Password:", "de": "Passwort:", "ru": "Пароль:", "pt": "Senha:", "nl": "Wachtwoord:", "fr": "Mot de passe:", "it": "Parola d'ordine:", "es": "Clave:", "pl": "Hasło:", "zh-cn": "密码:"},
|
||||||
"Password repeat:": {"en": "Password repeat:", "de": "Kennwort-Woederholung:", "ru": "Подтверждение пароля:"},
|
"Passwords missmatch!": { "en": "Passwords missmatch!", "de": "Passwörter stimmen nicht überein!", "ru": "Пароли не совпадают!", "pt": "As senhas não correspondem!", "nl": "Wachtwoorden komen niet overeen!", "fr": "Les mots de passe ne correspondent pas !", "it": "Le password non corrispondono!", "es": "¡Las contraseñas no coinciden!", "pl": "Niezgodność haseł!", "zh-cn": "密码不匹配!"},
|
||||||
"Passwords missmatch!": {"en": "Passwords missmatch!", "de": "Kennworte sind unterschiedlich!", "ru": "Пароли не совпадают!"},
|
"Secure:": { "en": "HTTPS?", "de": "HTTPS?", "ru": "HTTPS?", "pt": "HTTPS?", "nl": "HTTPS?", "fr": "HTTPS ?", "it": "HTTPS?", "es": "¿HTTPS?", "pl": "HTTPS?", "zh-cn": "HTTPS?"},
|
||||||
"Prompt:": {"en": "Prompt:", "de": "Prompt:", "ru": "Промпт:"},
|
|
||||||
"tooltip_password": {
|
|
||||||
"en": "Optional. Only if FHEM requires password.",
|
|
||||||
"de": "Optional. Nur falls in FHEM konfiguriert",
|
|
||||||
"ru": "Не обязательно. Только если настроено в FHEM"
|
|
||||||
},
|
|
||||||
"tooltip_prompt": {
|
|
||||||
"en": "You can change standard prompt from 'hass>' to something else.",
|
|
||||||
"de": "Man kann hier ein eigenes Prompt setzen. Default ist 'hass>'",
|
|
||||||
"ru": "Можно задать собственный промпт. По умолчанию 'hass>'"
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
+125
-191
@@ -1,3 +1,7 @@
|
|||||||
|
/*!
|
||||||
|
* ioBroker gulpfile
|
||||||
|
* Date: 2019-01-28
|
||||||
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const gulp = require('gulp');
|
const gulp = require('gulp');
|
||||||
@@ -5,15 +9,10 @@ const fs = require('fs');
|
|||||||
const pkg = require('./package.json');
|
const pkg = require('./package.json');
|
||||||
const iopackage = require('./io-package.json');
|
const iopackage = require('./io-package.json');
|
||||||
const version = (pkg && pkg.version) ? pkg.version : iopackage.common.version;
|
const version = (pkg && pkg.version) ? pkg.version : iopackage.common.version;
|
||||||
/*var appName = getAppName();
|
|
||||||
|
|
||||||
function getAppName() {
|
|
||||||
var parts = __dirname.replace(/\\/g, '/').split('/');
|
|
||||||
return parts[parts.length - 1].split('.')[0].toLowerCase();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
const fileName = 'words.js';
|
const fileName = 'words.js';
|
||||||
let languages = {
|
const EMPTY = '';
|
||||||
|
const translate = require('./lib/tools').translateText;
|
||||||
|
const languages = {
|
||||||
en: {},
|
en: {},
|
||||||
de: {},
|
de: {},
|
||||||
ru: {},
|
ru: {},
|
||||||
@@ -26,25 +25,18 @@ let languages = {
|
|||||||
'zh-cn': {}
|
'zh-cn': {}
|
||||||
};
|
};
|
||||||
|
|
||||||
function lang2data(lang, isFlat) {
|
function lang2data(lang) {
|
||||||
let str = isFlat ? '' : '{\n';
|
let str ='{\n';
|
||||||
let count = 0;
|
let count = 0;
|
||||||
for (const w in lang) {
|
for (const w in lang) {
|
||||||
if (lang.hasOwnProperty(w)) {
|
if (lang.hasOwnProperty(w)) {
|
||||||
count++;
|
count++;
|
||||||
if (isFlat) {
|
|
||||||
str += (lang[w] === '' ? (isFlat[w] || w) : lang[w]) + '\n';
|
|
||||||
} else {
|
|
||||||
const key = ' "' + w.replace(/"/g, '\\"') + '": ';
|
const key = ' "' + w.replace(/"/g, '\\"') + '": ';
|
||||||
str += key + '"' + lang[w].replace(/"/g, '\\"') + '",\n';
|
str += key + '"' + lang[w].replace(/"/g, '\\"') + '",\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (!count) {
|
if (!count) {
|
||||||
return isFlat ? '' : '{\n}';
|
return '{\n}';
|
||||||
}
|
|
||||||
if (isFlat) {
|
|
||||||
return str;
|
|
||||||
} else {
|
} else {
|
||||||
return str.substring(0, str.length - 2) + '\n}';
|
return str.substring(0, str.length - 2) + '\n}';
|
||||||
}
|
}
|
||||||
@@ -58,26 +50,9 @@ function readWordJs(src) {
|
|||||||
} else {
|
} else {
|
||||||
words = fs.readFileSync(src + fileName).toString();
|
words = fs.readFileSync(src + fileName).toString();
|
||||||
}
|
}
|
||||||
|
words = words.substring(words.indexOf('{'), words.length);
|
||||||
|
words = words.substring(0, words.lastIndexOf(';'));
|
||||||
|
|
||||||
const lines = words.split(/\r\n|\r|\n/g);
|
|
||||||
let i = 0;
|
|
||||||
while (!lines[i].match(/^systemDictionary = {/)) {
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
lines.splice(0, i);
|
|
||||||
|
|
||||||
// remove last empty lines
|
|
||||||
i = lines.length - 1;
|
|
||||||
while (!lines[i]) {
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
if (i < lines.length - 1) {
|
|
||||||
lines.splice(i + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
lines[0] = lines[0].replace('systemDictionary = ', '');
|
|
||||||
lines[lines.length - 1] = lines[lines.length - 1].trim().replace(/};$/, '}');
|
|
||||||
words = lines.join('\n');
|
|
||||||
const resultFunc = new Function('return ' + words + ';');
|
const resultFunc = new Function('return ' + words + ';');
|
||||||
|
|
||||||
return resultFunc();
|
return resultFunc();
|
||||||
@@ -85,14 +60,15 @@ function readWordJs(src) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function padRight(text, totalLength) {
|
function padRight(text, totalLength) {
|
||||||
return text + (text.length < totalLength ? new Array(totalLength - text.length).join(' ') : '');
|
return text + (text.length < totalLength ? new Array(totalLength - text.length).join(' ') : '');
|
||||||
}
|
}
|
||||||
function writeWordJs(data, src) {
|
|
||||||
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';
|
|
||||||
|
|
||||||
|
function writeWordJs(data, src) {
|
||||||
|
let text = '';
|
||||||
|
text += '/*global systemDictionary:true */\n';
|
||||||
|
text += "'use strict';\n\n";
|
||||||
text += 'systemDictionary = {\n';
|
text += 'systemDictionary = {\n';
|
||||||
for (const word in data) {
|
for (const word in data) {
|
||||||
if (data.hasOwnProperty(word)) {
|
if (data.hasOwnProperty(word)) {
|
||||||
@@ -110,9 +86,7 @@ function writeWordJs(data, src) {
|
|||||||
text += line + '},\n';
|
text += line + '},\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
text = text.replace(/},\n$/, '}\n');
|
|
||||||
text += '};';
|
text += '};';
|
||||||
|
|
||||||
if (fs.existsSync(src + 'js/' + fileName)) {
|
if (fs.existsSync(src + 'js/' + fileName)) {
|
||||||
fs.writeFileSync(src + 'js/' + fileName, text);
|
fs.writeFileSync(src + 'js/' + fileName, text);
|
||||||
} else {
|
} else {
|
||||||
@@ -120,8 +94,6 @@ function writeWordJs(data, src) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const EMPTY = '';
|
|
||||||
|
|
||||||
function words2languages(src) {
|
function words2languages(src) {
|
||||||
const langs = Object.assign({}, languages);
|
const langs = Object.assign({}, languages);
|
||||||
const data = readWordJs(src);
|
const data = readWordJs(src);
|
||||||
@@ -145,10 +117,11 @@ function words2languages(src) {
|
|||||||
fs.mkdirSync(src + 'i18n/');
|
fs.mkdirSync(src + 'i18n/');
|
||||||
}
|
}
|
||||||
for (const l in langs) {
|
for (const l in langs) {
|
||||||
if (!langs.hasOwnProperty(l)) continue;
|
if (!langs.hasOwnProperty(l))
|
||||||
|
continue;
|
||||||
const keys = Object.keys(langs[l]);
|
const keys = Object.keys(langs[l]);
|
||||||
//keys.sort();
|
keys.sort();
|
||||||
let obj = {};
|
const obj = {};
|
||||||
for (let k = 0; k < keys.length; k++) {
|
for (let k = 0; k < keys.length; k++) {
|
||||||
obj[keys[k]] = langs[l][keys[k]];
|
obj[keys[k]] = langs[l][keys[k]];
|
||||||
}
|
}
|
||||||
@@ -162,144 +135,36 @@ function words2languages(src) {
|
|||||||
console.error('Cannot read or parse ' + fileName);
|
console.error('Cannot read or parse ' + fileName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function words2languagesFlat(src) {
|
|
||||||
let langs = Object.assign({}, languages);
|
|
||||||
const data = readWordJs(src);
|
|
||||||
if (data) {
|
|
||||||
for (const word in data) {
|
|
||||||
if (data.hasOwnProperty(word)) {
|
|
||||||
for (const lang in data[word]) {
|
|
||||||
if (data[word].hasOwnProperty(lang)) {
|
|
||||||
langs[lang][word] = data[word][lang];
|
|
||||||
// pre-fill all other languages
|
|
||||||
for (const j in langs) {
|
|
||||||
if (langs.hasOwnProperty(j)) {
|
|
||||||
langs[j][word] = langs[j][word] || EMPTY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const keys = Object.keys(langs.en);
|
|
||||||
//keys.sort();
|
|
||||||
for (const l in langs) {
|
|
||||||
if (!langs.hasOwnProperty(l)) continue;
|
|
||||||
let obj = {};
|
|
||||||
for (let k = 0; k < keys.length; k++) {
|
|
||||||
obj[keys[k]] = langs[l][keys[k]];
|
|
||||||
}
|
|
||||||
langs[l] = obj;
|
|
||||||
}
|
|
||||||
if (!fs.existsSync(src + 'i18n/')) {
|
|
||||||
fs.mkdirSync(src + 'i18n/');
|
|
||||||
}
|
|
||||||
for (const ll in langs) {
|
|
||||||
if (!langs.hasOwnProperty(ll)) continue;
|
|
||||||
if (!fs.existsSync(src + 'i18n/' + ll)) {
|
|
||||||
fs.mkdirSync(src + 'i18n/' + ll);
|
|
||||||
}
|
|
||||||
|
|
||||||
fs.writeFileSync(src + 'i18n/' + ll + '/flat.txt', lang2data(langs[ll], langs.en));
|
|
||||||
}
|
|
||||||
fs.writeFileSync(src + 'i18n/flat.txt', keys.join('\n'));
|
|
||||||
} else {
|
|
||||||
console.error('Cannot read or parse ' + fileName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function languagesFlat2words(src) {
|
|
||||||
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;
|
|
||||||
return 0;
|
|
||||||
} else if (posA === -1) {
|
|
||||||
return -1;
|
|
||||||
} else if (posB === -1) {
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
if (posA > posB) return 1;
|
|
||||||
if (posA < posB) return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const keys = fs.readFileSync(src + 'i18n/flat.txt').toString().split('\n');
|
|
||||||
|
|
||||||
for (let l = 0; l < dirs.length; l++) {
|
|
||||||
if (dirs[l] === 'flat.txt') continue;
|
|
||||||
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');
|
|
||||||
});
|
|
||||||
|
|
||||||
const words = langs[lang];
|
|
||||||
for (const word in words) {
|
|
||||||
if (words.hasOwnProperty(word)) {
|
|
||||||
bigOne[word] = bigOne[word] || {};
|
|
||||||
if (words[word] !== EMPTY) {
|
|
||||||
bigOne[word][lang] = words[word];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// read actual words.js
|
|
||||||
const aWords = readWordJs();
|
|
||||||
|
|
||||||
const temporaryIgnore = ['pt', 'fr', 'nl', 'flat.txt'];
|
|
||||||
if (aWords) {
|
|
||||||
// Merge words together
|
|
||||||
for (const w in aWords) {
|
|
||||||
if (aWords.hasOwnProperty(w)) {
|
|
||||||
if (!bigOne[w]) {
|
|
||||||
console.warn('Take from actual words.js: ' + w);
|
|
||||||
bigOne[w] = aWords[w]
|
|
||||||
}
|
|
||||||
dirs.forEach(function (lang) {
|
|
||||||
if (temporaryIgnore.indexOf(lang) !== -1) return;
|
|
||||||
if (!bigOne[w][lang]) {
|
|
||||||
console.warn('Missing "' + lang + '": ' + w);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
writeWordJs(bigOne, src);
|
|
||||||
}
|
|
||||||
function languages2words(src) {
|
function languages2words(src) {
|
||||||
const dirs = fs.readdirSync(src + 'i18n/');
|
const dirs = fs.readdirSync(src + 'i18n/');
|
||||||
let langs = {};
|
const langs = {};
|
||||||
let bigOne = {};
|
const bigOne = {};
|
||||||
const order = Object.keys(languages);
|
const order = Object.keys(languages);
|
||||||
dirs.sort((a, b) => {
|
dirs.sort(function (a, b) {
|
||||||
const posA = order.indexOf(a);
|
const posA = order.indexOf(a);
|
||||||
const posB = order.indexOf(b);
|
const posB = order.indexOf(b);
|
||||||
if (posA === -1 && posB === -1) {
|
if (posA === -1 && posB === -1) {
|
||||||
if (a > b) return 1;
|
if (a > b)
|
||||||
if (a < b) return -1;
|
return 1;
|
||||||
|
if (a < b)
|
||||||
|
return -1;
|
||||||
return 0;
|
return 0;
|
||||||
} else if (posA === -1) {
|
} else if (posA === -1) {
|
||||||
return -1;
|
return -1;
|
||||||
} else if (posB === -1) {
|
} else if (posB === -1) {
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
if (posA > posB) return 1;
|
if (posA > posB)
|
||||||
if (posA < posB) return -1;
|
return 1;
|
||||||
|
if (posA < posB)
|
||||||
|
return -1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
for (let l = 0; l < dirs.length; l++) {
|
for (const lang of dirs) {
|
||||||
if (dirs[l] === 'flat.txt') continue;
|
if (lang === 'flat.txt')
|
||||||
const lang = dirs[l];
|
continue;
|
||||||
langs[lang] = fs.readFileSync(src + 'i18n/' + lang + '/translations.json').toString();
|
langs[lang] = fs.readFileSync(src + 'i18n/' + lang + '/translations.json').toString();
|
||||||
langs[lang] = JSON.parse(langs[lang]);
|
langs[lang] = JSON.parse(langs[lang]);
|
||||||
const words = langs[lang];
|
const words = langs[lang];
|
||||||
@@ -315,17 +180,18 @@ function languages2words(src) {
|
|||||||
// read actual words.js
|
// read actual words.js
|
||||||
const aWords = readWordJs();
|
const aWords = readWordJs();
|
||||||
|
|
||||||
const temporaryIgnore = ['pt', 'fr', 'nl', 'it'];
|
const temporaryIgnore = ['flat.txt'];
|
||||||
if (aWords) {
|
if (aWords) {
|
||||||
// Merge words together
|
// Merge words together
|
||||||
for (const w in aWords) {
|
for (const w in aWords) {
|
||||||
if (aWords.hasOwnProperty(w)) {
|
if (aWords.hasOwnProperty(w)) {
|
||||||
if (!bigOne[w]) {
|
if (!bigOne[w]) {
|
||||||
console.warn('Take from actual words.js: ' + w);
|
console.warn('Take from actual words.js: ' + w);
|
||||||
bigOne[w] = aWords[w]
|
bigOne[w] = aWords[w];
|
||||||
}
|
}
|
||||||
dirs.forEach(function (lang) {
|
dirs.forEach(function (lang) {
|
||||||
if (temporaryIgnore.indexOf(lang) !== -1) return;
|
if (temporaryIgnore.indexOf(lang) !== -1)
|
||||||
|
return;
|
||||||
if (!bigOne[w][lang]) {
|
if (!bigOne[w][lang]) {
|
||||||
console.warn('Missing "' + lang + '": ' + w);
|
console.warn('Missing "' + lang + '": ' + w);
|
||||||
}
|
}
|
||||||
@@ -338,37 +204,53 @@ function languages2words(src) {
|
|||||||
writeWordJs(bigOne, src);
|
writeWordJs(bigOne, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
gulp.task('admin (words.js => json)', done => {
|
async function translateNotExisting(obj, baseText, yandex) {
|
||||||
|
let t = obj['en'];
|
||||||
|
if (!t) {
|
||||||
|
t = baseText;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t) {
|
||||||
|
for (let l in languages) {
|
||||||
|
if (!obj[l]) {
|
||||||
|
const time = new Date().getTime();
|
||||||
|
obj[l] = await translate(t, l, yandex);
|
||||||
|
console.log('en -> ' + l + ' ' + (new Date().getTime() - time) + ' ms');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TASKS
|
||||||
|
|
||||||
|
gulp.task('adminWords2languages', function (done) {
|
||||||
words2languages('./admin/');
|
words2languages('./admin/');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('admin (words.js => flat)', done => {
|
gulp.task('adminLanguages2words', function (done) {
|
||||||
words2languagesFlat('./admin/');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('admin (flat => words.js)', done => {
|
|
||||||
languagesFlat2words('./admin/');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('admin (json => words.js)', done => {
|
|
||||||
languages2words('./admin/');
|
languages2words('./admin/');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('updatePackages', done => {
|
gulp.task('updatePackages', function (done) {
|
||||||
iopackage.common.version = pkg.version;
|
iopackage.common.version = pkg.version;
|
||||||
iopackage.common.news = iopackage.common.news || {};
|
iopackage.common.news = iopackage.common.news || {};
|
||||||
if (!iopackage.common.news[pkg.version]) {
|
if (!iopackage.common.news[pkg.version]) {
|
||||||
const news = iopackage.common.news;
|
const news = iopackage.common.news;
|
||||||
let newNews = {};
|
const newNews = {};
|
||||||
|
|
||||||
newNews[pkg.version] = {
|
newNews[pkg.version] = {
|
||||||
en: 'news',
|
en: 'news',
|
||||||
de: 'neues',
|
de: 'neues',
|
||||||
ru: 'новое'
|
ru: 'новое',
|
||||||
|
pt: 'novidades',
|
||||||
|
nl: 'nieuws',
|
||||||
|
fr: 'nouvelles',
|
||||||
|
it: 'notizie',
|
||||||
|
es: 'noticias',
|
||||||
|
pl: 'nowości',
|
||||||
|
'zh-cn': '新'
|
||||||
};
|
};
|
||||||
iopackage.common.news = Object.assign(newNews, news);
|
iopackage.common.news = Object.assign(newNews, news);
|
||||||
}
|
}
|
||||||
@@ -376,12 +258,12 @@ gulp.task('updatePackages', done => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('updateReadme', done => {
|
gulp.task('updateReadme', function (done) {
|
||||||
const readme = fs.readFileSync('README.md').toString();
|
const readme = fs.readFileSync('README.md').toString();
|
||||||
const pos = readme.indexOf('## Changelog\n');
|
const pos = readme.indexOf('## Changelog\n');
|
||||||
if (pos !== -1) {
|
if (pos !== -1) {
|
||||||
let readmeStart = readme.substring(0, pos + '## Changelog\n'.length);
|
const readmeStart = readme.substring(0, pos + '## Changelog\n'.length);
|
||||||
let readmeEnd = readme.substring(pos + '## Changelog\n'.length);
|
const readmeEnd = readme.substring(pos + '## Changelog\n'.length);
|
||||||
|
|
||||||
if (readme.indexOf(version) === -1) {
|
if (readme.indexOf(version) === -1) {
|
||||||
const timestamp = new Date();
|
const timestamp = new Date();
|
||||||
@@ -400,4 +282,56 @@ gulp.task('updateReadme', done => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
gulp.task('translate', async function (done) {
|
||||||
|
|
||||||
|
let yandex;
|
||||||
|
const i = process.argv.indexOf('--yandex');
|
||||||
|
if (i > -1) {
|
||||||
|
yandex = process.argv[i + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iopackage && iopackage.common) {
|
||||||
|
if (iopackage.common.news) {
|
||||||
|
console.log('Translate News');
|
||||||
|
for (let k in iopackage.common.news) {
|
||||||
|
console.log('News: ' + k);
|
||||||
|
let nw = iopackage.common.news[k];
|
||||||
|
await translateNotExisting(nw, null, yandex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (iopackage.common.titleLang) {
|
||||||
|
console.log('Translate Title');
|
||||||
|
await translateNotExisting(iopackage.common.titleLang, iopackage.common.title, yandex);
|
||||||
|
}
|
||||||
|
if (iopackage.common.desc) {
|
||||||
|
console.log('Translate Description');
|
||||||
|
await translateNotExisting(iopackage.common.desc, null, yandex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fs.existsSync('./admin/i18n/en/translations.json')) {
|
||||||
|
let enTranslations = require('./admin/i18n/en/translations.json');
|
||||||
|
for (let l in languages) {
|
||||||
|
console.log('Translate Text: ' + l);
|
||||||
|
let existing = {};
|
||||||
|
if (fs.existsSync('./admin/i18n/' + l + '/translations.json')) {
|
||||||
|
existing = require('./admin/i18n/' + l + '/translations.json');
|
||||||
|
}
|
||||||
|
for (let t in enTranslations) {
|
||||||
|
if (!existing[t]) {
|
||||||
|
existing[t] = await translate(enTranslations[t], l, yandex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!fs.existsSync('./admin/i18n/' + l + '/')) {
|
||||||
|
fs.mkdirSync('./admin/i18n/' + l + '/');
|
||||||
|
}
|
||||||
|
fs.writeFileSync('./admin/i18n/' + l + '/translations.json', JSON.stringify(existing, null, 4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
fs.writeFileSync('io-package.json', JSON.stringify(iopackage, null, 4));
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('translateAndUpdateWordsJS', gulp.series('translate', 'adminLanguages2words', 'adminWords2languages'));
|
||||||
|
|
||||||
gulp.task('default', gulp.series('updatePackages', 'updateReadme'));
|
gulp.task('default', gulp.series('updatePackages', 'updateReadme'));
|
||||||
+75
-5
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"common": {
|
"common": {
|
||||||
"name": "hass",
|
"name": "hass",
|
||||||
"version": "1.0.1",
|
"version": "1.1.0",
|
||||||
"title": "Home Assistant",
|
"title": "Home Assistant",
|
||||||
"titleLang": {
|
"titleLang": {
|
||||||
"en": "Home Assistant",
|
"en": "Home Assistant",
|
||||||
@@ -24,9 +24,22 @@
|
|||||||
"fr": "Connexion Home Assistant pour ioBroker",
|
"fr": "Connexion Home Assistant pour ioBroker",
|
||||||
"it": "Connessione Home Assistant per ioBroker",
|
"it": "Connessione Home Assistant per ioBroker",
|
||||||
"es": "Conexión de Home Assistant para ioBroker",
|
"es": "Conexión de Home Assistant para ioBroker",
|
||||||
"pl": "Połączenie Home Assistant dla ioBroker"
|
"pl": "Połączenie Home Assistant dla ioBroker",
|
||||||
|
"zh-cn": "ioBroker 的家庭助理连接"
|
||||||
},
|
},
|
||||||
"news": {
|
"news": {
|
||||||
|
"1.1.0": {
|
||||||
|
"en": "IMPORTANT: You need to re-enter the password once after installing this version!\nImplement Service triggers to use any value to trigger or stringified JSON to call with fields\nOptimize unload handling\nAdd Sentry for crash reporting",
|
||||||
|
"de": "WICHTIG: Nach der Installation dieser Version müssen Sie das Passwort einmalig neu eingeben!\nImplementieren Sie Dienstauslöser, um einen beliebigen Wert zum Auslösen oder stringifiziertes JSON zum Aufrufen mit Feldern zu verwenden\nEntladehandling optimieren\nFügen Sie Sentry für Absturzberichte hinzu",
|
||||||
|
"ru": "ВАЖНО: Вам необходимо повторно ввести пароль один раз после установки этой версии!\nРеализовать триггеры службы, чтобы использовать любое значение для запуска или строкового JSON для вызова с полями.\nОптимизация обработки разгрузки\nДобавьте Sentry для отчетов о сбоях",
|
||||||
|
"pt": "IMPORTANTE: Você precisa redigitar a senha uma vez depois de instalar esta versão!\nImplemente gatilhos de serviço para usar qualquer valor para acionar ou JSON stringified para chamar com campos\nOtimize o manuseio de descarga\nAdicionar Sentinela para relatórios de falhas",
|
||||||
|
"nl": "BELANGRIJK: u moet het wachtwoord één keer opnieuw invoeren na het installeren van deze versie!\nImplementeer servicetriggers om elke waarde te gebruiken om te activeren of stringified JSON om met velden aan te roepen\nOptimaliseer de losverwerking\nSentry toevoegen voor crashrapportage",
|
||||||
|
"fr": "IMPORTANT : Vous devez ressaisir le mot de passe une fois après l'installation de cette version !\nImplémentez des déclencheurs de service pour utiliser n'importe quelle valeur pour déclencher ou JSON stringifié pour appeler avec des champs\nOptimiser la gestion des déchargements\nAjouter Sentry pour les rapports de plantage",
|
||||||
|
"it": "IMPORTANTE: è necessario reinserire la password una volta dopo aver installato questa versione!\nImplementa i trigger del servizio per utilizzare qualsiasi valore per attivare o JSON in formato stringa per chiamare con i campi\nOttimizza la gestione dello scarico\nAggiungi Sentinella per la segnalazione degli arresti anomali",
|
||||||
|
"es": "IMPORTANTE: ¡Debe volver a ingresar la contraseña una vez después de instalar esta versión!\nImplementar disparadores de servicio para usar cualquier valor para disparar o JSON en cadena para llamar con campos\nOptimizar el manejo de descarga\nAgregar Sentry para informes de fallas",
|
||||||
|
"pl": "WAŻNE: Po zainstalowaniu tej wersji należy raz ponownie wprowadzić hasło!\nZaimplementuj wyzwalacze usługi, aby używać dowolnej wartości do wyzwalania lub skróconego JSON do wywołania z polami\nZoptymalizuj obsługę rozładunku\nDodaj Sentry do zgłaszania awarii",
|
||||||
|
"zh-cn": "重要提示:安装此版本后需要重新输入一次密码!\n实现服务触发器以使用任何值触发或字符串化 JSON 以使用字段调用\n优化卸载处理\n添加 Sentry 以进行崩溃报告"
|
||||||
|
},
|
||||||
"1.0.1": {
|
"1.0.1": {
|
||||||
"en": "IMPORTANT: js-controller 2.0 is needed st least!\nFix start issue\n(Apollon77/Garfonso) Fix issue where value could not be set in hass",
|
"en": "IMPORTANT: js-controller 2.0 is needed st least!\nFix start issue\n(Apollon77/Garfonso) Fix issue where value could not be set in hass",
|
||||||
"de": "WICHTIG: js-controller 2.0 wird am wenigsten benötigt!\nStartproblem beheben\n(Apollon77/Garfonso) Problem behoben, bei dem der Wert nicht in Hass festgelegt werden konnte",
|
"de": "WICHTIG: js-controller 2.0 wird am wenigsten benötigt!\nStartproblem beheben\n(Apollon77/Garfonso) Problem behoben, bei dem der Wert nicht in Hass festgelegt werden konnte",
|
||||||
@@ -60,7 +73,8 @@
|
|||||||
"fr": "version initiale",
|
"fr": "version initiale",
|
||||||
"it": "versione iniziale",
|
"it": "versione iniziale",
|
||||||
"es": "versión inicial",
|
"es": "versión inicial",
|
||||||
"pl": "początkowa wersja"
|
"pl": "początkowa wersja",
|
||||||
|
"zh-cn": "初始版本"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"localLink": "http://%host%:8123",
|
"localLink": "http://%host%:8123",
|
||||||
@@ -85,12 +99,62 @@
|
|||||||
],
|
],
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
{
|
{
|
||||||
"js-controller": ">=2.0.0"
|
"js-controller": ">=3.0.0"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"globalDependencies": [
|
||||||
|
{
|
||||||
|
"admin": ">=5.1.28"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"plugins": {
|
||||||
|
"sentry": {
|
||||||
|
"dsn": "https://1b2a1e8335f84cc49a67dd5ac2b07573@sentry.iobroker.net/182"
|
||||||
|
}
|
||||||
|
},
|
||||||
"connectionType": "local",
|
"connectionType": "local",
|
||||||
"dataSource": "push",
|
"dataSource": "push",
|
||||||
"tier": 2
|
"tier": 2,
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"condition": {
|
||||||
|
"operand": "and",
|
||||||
|
"rules": [
|
||||||
|
"oldVersion<1.1.0",
|
||||||
|
"newVersion>=1.1.0"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"en": "Re-enter the password after Update!",
|
||||||
|
"de": "Passwort muss nach dem Update erneut eingegeben werden!",
|
||||||
|
"ru": "Повторно введите пароль после обновления!",
|
||||||
|
"pt": "Digite novamente a senha após Atualizar!",
|
||||||
|
"nl": "Voer het wachtwoord opnieuw in na Update!",
|
||||||
|
"fr": "Entrez à nouveau le mot de passe après la mise à jour !",
|
||||||
|
"it": "Reinserire la password dopo l'aggiornamento!",
|
||||||
|
"es": "Vuelva a ingresar la contraseña después de ¡Actualizar!",
|
||||||
|
"pl": "Wprowadź hasło ponownie po aktualizacji!",
|
||||||
|
"zh-cn": "更新后重新输入密码!"
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"en": "After installing this update the password/token used to access the HASS installation needs to be re-entered in the Instance-Settings!",
|
||||||
|
"de": "Nach der Installation dieses Updates muss das Passwort/Token für den Zugriff auf die HASS-Installation in den Instanz-Einstellungen erneut eingegeben werden!",
|
||||||
|
"ru": "После установки этого обновления пароль/токен, используемый для доступа к установке HASS, необходимо повторно ввести в настройках экземпляра!",
|
||||||
|
"pt": "Depois de instalar esta atualização, a senha/token usado para acessar a instalação do HASS precisa ser reinserido nas configurações da instância!",
|
||||||
|
"nl": "Na het installeren van deze update moet het wachtwoord/token dat wordt gebruikt om toegang te krijgen tot de HASS-installatie opnieuw worden ingevoerd in de Instance-Settings!",
|
||||||
|
"fr": "Après l'installation de cette mise à jour, le mot de passe/jeton utilisé pour accéder à l'installation HASS doit être ressaisi dans les paramètres d'instance !",
|
||||||
|
"it": "Dopo aver installato questo aggiornamento, la password/token utilizzato per accedere all'installazione HASS deve essere reinserito nelle impostazioni dell'istanza!",
|
||||||
|
"es": "¡Después de instalar esta actualización, la contraseña/token utilizada para acceder a la instalación de HASS debe volver a ingresarse en la configuración de la instancia!",
|
||||||
|
"pl": "Po zainstalowaniu tej aktualizacji hasło/token używane do uzyskania dostępu do instalacji HASS należy ponownie wprowadzić w ustawieniach instancji!",
|
||||||
|
"zh-cn": "安装此更新后,用于访问 HASS 安装的密码/令牌需要在实例设置中重新输入!"
|
||||||
|
},
|
||||||
|
"level": "warn",
|
||||||
|
"buttons": [
|
||||||
|
"agree",
|
||||||
|
"cancel"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"native": {
|
"native": {
|
||||||
"host": "127.0.0.1",
|
"host": "127.0.0.1",
|
||||||
@@ -98,6 +162,12 @@
|
|||||||
"password": "",
|
"password": "",
|
||||||
"secure": false
|
"secure": false
|
||||||
},
|
},
|
||||||
|
"protectedNative": [
|
||||||
|
"password"
|
||||||
|
],
|
||||||
|
"encryptedNative": [
|
||||||
|
"password"
|
||||||
|
],
|
||||||
"objects": [],
|
"objects": [],
|
||||||
"instanceObjects": [
|
"instanceObjects": [
|
||||||
{
|
{
|
||||||
|
|||||||
+5
-4
@@ -92,7 +92,7 @@ function HASS(options, log) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function callService(socket, service, domain, serviceData, callback) {
|
function callService(socket, service, domain, serviceData, target, callback) {
|
||||||
if (socket && typeof socket.send === 'function') {
|
if (socket && typeof socket.send === 'function') {
|
||||||
const id = currentId++;
|
const id = currentId++;
|
||||||
requests[id] = {type: 'call_service', cb: callback, ts: Date.now()};
|
requests[id] = {type: 'call_service', cb: callback, ts: Date.now()};
|
||||||
@@ -101,7 +101,8 @@ function HASS(options, log) {
|
|||||||
type: 'call_service',
|
type: 'call_service',
|
||||||
domain: domain || '',
|
domain: domain || '',
|
||||||
service: service,
|
service: service,
|
||||||
service_data: serviceData
|
service_data: serviceData,
|
||||||
|
target
|
||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
callback && callback('not connected');
|
callback && callback('not connected');
|
||||||
@@ -228,11 +229,11 @@ function HASS(options, log) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.callService = function (service, domain, serviceData, callback) {
|
this.callService = function (service, domain, serviceData, target, callback) {
|
||||||
if (!connected) {
|
if (!connected) {
|
||||||
typeof callback === 'function' && callback('not connected');
|
typeof callback === 'function' && callback('not connected');
|
||||||
} else {
|
} else {
|
||||||
callService(this.socket, service, domain, serviceData, callback);
|
callService(this.socket, service, domain, serviceData, target, callback);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,92 @@
|
|||||||
|
const axios = require("axios");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests whether the given variable is a real object and not an Array
|
||||||
|
* @param {any} it The variable to test
|
||||||
|
* @returns {it is Record<string, any>}
|
||||||
|
*/
|
||||||
|
function isObject(it) {
|
||||||
|
// This is necessary because:
|
||||||
|
// typeof null === 'object'
|
||||||
|
// typeof [] === 'object'
|
||||||
|
// [] instanceof Object === true
|
||||||
|
return Object.prototype.toString.call(it) === "[object Object]";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests whether the given variable is really an Array
|
||||||
|
* @param {any} it The variable to test
|
||||||
|
* @returns {it is any[]}
|
||||||
|
*/
|
||||||
|
function isArray(it) {
|
||||||
|
if (Array.isArray != null)
|
||||||
|
return Array.isArray(it);
|
||||||
|
return Object.prototype.toString.call(it) === "[object Array]";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Choose the right tranalation API
|
||||||
|
* @param {string} text The text to translate
|
||||||
|
* @param {string} targetLang The target languate
|
||||||
|
* @param {string} yandex api key
|
||||||
|
* @returns {Promise<string>}
|
||||||
|
*/
|
||||||
|
async function translateText(text, targetLang, yandex) {
|
||||||
|
if (targetLang === "en") {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
if (yandex) {
|
||||||
|
return await translateYandex(text, targetLang, yandex);
|
||||||
|
} else {
|
||||||
|
return await translateGoogle(text, targetLang);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translates text with Yandex API
|
||||||
|
* @param {string} text The text to translate
|
||||||
|
* @param {string} targetLang The target languate
|
||||||
|
* @param {string} yandex api key
|
||||||
|
* @returns {Promise<string>}
|
||||||
|
*/
|
||||||
|
async function translateYandex(text, targetLang, yandex) {
|
||||||
|
if (targetLang === "zh-cn") {
|
||||||
|
targetLang = "zh";
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const url = `https://translate.yandex.net/api/v1.5/tr.json/translate?key=${yandex}&text=${encodeURIComponent(text)}&lang=en-${targetLang}`;
|
||||||
|
const response = await axios({url, timeout: 15000});
|
||||||
|
if (response.data && response.data['text']) {
|
||||||
|
return response.data['text'][0];
|
||||||
|
}
|
||||||
|
throw new Error("Invalid response for translate request");
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error(`Could not translate to "${targetLang}": ${e}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translates text with Google API
|
||||||
|
* @param {string} text The text to translate
|
||||||
|
* @param {string} targetLang The target languate
|
||||||
|
* @returns {Promise<string>}
|
||||||
|
*/
|
||||||
|
async function translateGoogle(text, targetLang) {
|
||||||
|
try {
|
||||||
|
const url = `http://translate.googleapis.com/translate_a/single?client=gtx&sl=en&tl=${targetLang}&dt=t&q=${encodeURIComponent(text)}&ie=UTF-8&oe=UTF-8`;
|
||||||
|
const response = await axios({url, timeout: 15000});
|
||||||
|
if (isArray(response.data)) {
|
||||||
|
// we got a valid response
|
||||||
|
return response.data[0][0][0];
|
||||||
|
}
|
||||||
|
throw new Error("Invalid response for translate request");
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error(`Could not translate to "${targetLang}": ${e}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
isArray,
|
||||||
|
isObject,
|
||||||
|
translateText
|
||||||
|
};
|
||||||
@@ -12,6 +12,8 @@ let connected = false;
|
|||||||
let hass;
|
let hass;
|
||||||
let adapter;
|
let adapter;
|
||||||
const hassObjects = {};
|
const hassObjects = {};
|
||||||
|
let delayTimeout = null;
|
||||||
|
let stopped = false;
|
||||||
|
|
||||||
function startAdapter(options) {
|
function startAdapter(options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
@@ -35,6 +37,17 @@ function startAdapter(options) {
|
|||||||
} else {
|
} else {
|
||||||
const serviceData = {};
|
const serviceData = {};
|
||||||
const fields = hassObjects[id].native.fields;
|
const fields = hassObjects[id].native.fields;
|
||||||
|
const target = {};
|
||||||
|
|
||||||
|
let requestFields = {};
|
||||||
|
if (typeof state.val === 'string') {
|
||||||
|
try {
|
||||||
|
requestFields = JSON.parse(state.val);
|
||||||
|
} catch (err) {
|
||||||
|
adapter.log.info(`Ignore data for service call ${id} is no valid JSON: ${err.message}`);
|
||||||
|
requestFields = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (const field in fields) {
|
for (const field in fields) {
|
||||||
if (!fields.hasOwnProperty(field)) {
|
if (!fields.hasOwnProperty(field)) {
|
||||||
@@ -42,15 +55,15 @@ function startAdapter(options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (field === 'entity_id') {
|
if (field === 'entity_id') {
|
||||||
serviceData.entity_id = hassObjects[id].native.entity_id
|
target.entity_id = hassObjects[id].native.entity_id
|
||||||
} else {
|
} else if (requestFields[field] !== undefined) {
|
||||||
serviceData[field] = state.val;
|
serviceData[field] = requestFields[field];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
serviceData.entity_id = hassObjects[id].native.entity_id
|
serviceData.entity_id = hassObjects[id].native.entity_id
|
||||||
|
|
||||||
adapter.log.debug(`Send to HASS for service ${hassObjects[id].native.attr} with ${hassObjects[id].native.domain || hassObjects[id].native.type} and data ${JSON.stringify(serviceData)}`)
|
adapter.log.debug(`Send to HASS for service ${hassObjects[id].native.attr} with ${hassObjects[id].native.domain || hassObjects[id].native.type} and data ${JSON.stringify(serviceData)}`)
|
||||||
hass.callService(hassObjects[id].native.attr, hassObjects[id].native.domain || hassObjects[id].native.type, serviceData, err =>
|
hass.callService(hassObjects[id].native.attr, hassObjects[id].native.domain || hassObjects[id].native.type, serviceData, target, err =>
|
||||||
err && adapter.log.error('Cannot control ' + id + ': ' + err));
|
err && adapter.log.error('Cannot control ' + id + ': ' + err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -65,6 +78,8 @@ function startAdapter(options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function stop(callback) {
|
function stop(callback) {
|
||||||
|
stopped = true;
|
||||||
|
delayTimeout && clearTimeout(delayTimeout);
|
||||||
hass && hass.close();
|
hass && hass.close();
|
||||||
callback && callback();
|
callback && callback();
|
||||||
}
|
}
|
||||||
@@ -318,7 +333,8 @@ function parseStates(entities, services, callback) {
|
|||||||
common: {
|
common: {
|
||||||
desc: service[s].description,
|
desc: service[s].description,
|
||||||
read: false,
|
read: false,
|
||||||
write: true
|
write: true,
|
||||||
|
type: 'mixed'
|
||||||
},
|
},
|
||||||
native: {
|
native: {
|
||||||
object_id: entity.object_id,
|
object_id: entity.object_id,
|
||||||
@@ -355,6 +371,10 @@ function main() {
|
|||||||
|
|
||||||
hass.on('state_changed', entity => {
|
hass.on('state_changed', entity => {
|
||||||
adapter.log.debug(`HASS-Message: State Changed: ${JSON.stringify(entity)}`);
|
adapter.log.debug(`HASS-Message: State Changed: ${JSON.stringify(entity)}`);
|
||||||
|
if (!entity || typeof entity.entity_id !== 'string') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const id = adapter.namespace + '.entities.' + entity.entity_id + '.';
|
const id = adapter.namespace + '.entities.' + entity.entity_id + '.';
|
||||||
const lc = entity.last_changed ? new Date(entity.last_changed).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;
|
const ts = entity.last_updated ? new Date(entity.last_updated).getTime() : undefined;
|
||||||
@@ -386,14 +406,22 @@ function main() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//adapter.log.debug(JSON.stringify(config));
|
//adapter.log.debug(JSON.stringify(config));
|
||||||
setTimeout(() =>
|
delayTimeout = setTimeout(() => {
|
||||||
hass.getStates((err, states) => {
|
delayTimeout = null;
|
||||||
|
!stopped && hass.getStates((err, states) => {
|
||||||
|
if (stopped) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (err) {
|
if (err) {
|
||||||
return adapter.log.error('Cannot read states: ' + err);
|
return adapter.log.error('Cannot read states: ' + err);
|
||||||
}
|
}
|
||||||
//adapter.log.debug(JSON.stringify(states));
|
//adapter.log.debug(JSON.stringify(states));
|
||||||
setTimeout(() =>
|
delayTimeout = setTimeout(() => {
|
||||||
hass.getServices((err, services) => {
|
delayTimeout = null;
|
||||||
|
!stopped && hass.getServices((err, services) => {
|
||||||
|
if (stopped) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (err) {
|
if (err) {
|
||||||
adapter.log.error('Cannot read states: ' + err);
|
adapter.log.error('Cannot read states: ' + err);
|
||||||
} else {
|
} else {
|
||||||
@@ -403,8 +431,8 @@ function main() {
|
|||||||
adapter.subscribeStates('*');
|
adapter.subscribeStates('*');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}), 100);
|
})}, 100);
|
||||||
}), 100);
|
})}, 100);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
+13
-7
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "iobroker.hass",
|
"name": "iobroker.hass",
|
||||||
"version": "1.0.1",
|
"version": "1.1.0",
|
||||||
"description": "Home Assistant",
|
"description": "Home Assistant",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "bluefox",
|
"name": "bluefox",
|
||||||
@@ -26,19 +26,25 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"websocket": "^1.0.34",
|
"websocket": "^1.0.34",
|
||||||
"ws": "^8.2.1",
|
"ws": "^8.5.0",
|
||||||
"@iobroker/adapter-core": "^2.5.1"
|
"@iobroker/adapter-core": "^2.6.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@alcalzone/release-script": "^2.2.1",
|
"@alcalzone/release-script": "^3.5.6",
|
||||||
|
"@alcalzone/release-script-plugin-iobroker": "^3.5.7",
|
||||||
|
"@alcalzone/release-script-plugin-license": "^3.5.3",
|
||||||
|
"axios": "^0.26.1",
|
||||||
"gulp": "^4.0.2",
|
"gulp": "^4.0.2",
|
||||||
"mocha": "^9.1.1",
|
"mocha": "^9.2.2",
|
||||||
"chai": "^4.3.4"
|
"chai": "^4.3.6"
|
||||||
},
|
},
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"scripts": {
|
"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"
|
"release": "release-script",
|
||||||
|
"release-patch": "release-script patch --yes",
|
||||||
|
"release-minor": "release-script minor --yes",
|
||||||
|
"release-major": "release-script major --yes"
|
||||||
},
|
},
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/ioBroker/ioBroker.hass/issues"
|
"url": "https://github.com/ioBroker/ioBroker.hass/issues"
|
||||||
|
|||||||
+330
-91
@@ -1,33 +1,52 @@
|
|||||||
/* jshint -W097 */// jshint strict:false
|
/* jshint -W097 */// jshint strict:false
|
||||||
/*jslint node: true */
|
/*jslint node: true */
|
||||||
// check if tmp directory exists
|
// check if tmp directory exists
|
||||||
var fs = require('fs');
|
const fs = require('fs');
|
||||||
var path = require('path');
|
const path = require('path');
|
||||||
var child_process = require('child_process');
|
const child_process = require('child_process');
|
||||||
var rootDir = path.normalize(__dirname + '/../../');
|
const rootDir = path.normalize(__dirname + '/../../');
|
||||||
var pkg = require(rootDir + 'package.json');
|
const pkg = require(rootDir + 'package.json');
|
||||||
var debug = typeof v8debug === 'object';
|
const debug = typeof v8debug === 'object';
|
||||||
pkg.main = pkg.main || 'main.js';
|
pkg.main = pkg.main || 'main.js';
|
||||||
|
|
||||||
var adapterName = path.normalize(rootDir).replace(/\\/g, '/').split('/');
|
let JSONLDB;
|
||||||
|
|
||||||
|
let adapterName = path.normalize(rootDir).replace(/\\/g, '/').split('/');
|
||||||
adapterName = adapterName[adapterName.length - 2];
|
adapterName = adapterName[adapterName.length - 2];
|
||||||
var adapterStarted = false;
|
let adapterStarted = false;
|
||||||
|
|
||||||
function getAppName() {
|
function getAppName() {
|
||||||
var parts = __dirname.replace(/\\/g, '/').split('/');
|
const parts = __dirname.replace(/\\/g, '/').split('/');
|
||||||
return parts[parts.length - 3].split('.')[0];
|
return parts[parts.length - 3].split('.')[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
var appName = getAppName().toLowerCase();
|
function loadJSONLDB() {
|
||||||
|
if (!JSONLDB) {
|
||||||
|
const dbPath = require.resolve('@alcalzone/jsonl-db', {
|
||||||
|
paths: [rootDir + 'tmp/node_modules', rootDir, rootDir + 'tmp/node_modules/' + appName + '.js-controller']
|
||||||
|
});
|
||||||
|
console.log('JSONLDB path: ' + dbPath);
|
||||||
|
try {
|
||||||
|
const { JsonlDB } = require(dbPath);
|
||||||
|
JSONLDB = JsonlDB;
|
||||||
|
} catch (err) {
|
||||||
|
console.log('Jsonl require error: ' + err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var objects;
|
const appName = getAppName().toLowerCase();
|
||||||
var states;
|
|
||||||
|
|
||||||
var pid = null;
|
let objects;
|
||||||
|
let states;
|
||||||
|
|
||||||
|
let pid = null;
|
||||||
|
|
||||||
|
let systemConfig = null;
|
||||||
|
|
||||||
function copyFileSync(source, target) {
|
function copyFileSync(source, target) {
|
||||||
|
|
||||||
var targetFile = target;
|
let targetFile = target;
|
||||||
|
|
||||||
//if target is a directory a new file with the same name will be created
|
//if target is a directory a new file with the same name will be created
|
||||||
if (fs.existsSync(target)) {
|
if (fs.existsSync(target)) {
|
||||||
@@ -40,19 +59,19 @@ function copyFileSync(source, target) {
|
|||||||
fs.writeFileSync(targetFile, fs.readFileSync(source));
|
fs.writeFileSync(targetFile, fs.readFileSync(source));
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
console.log("file copy error: " +source +" -> " + targetFile + " (error ignored)");
|
console.log('file copy error: ' +source +' -> ' + targetFile + ' (error ignored)');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function copyFolderRecursiveSync(source, target, ignore) {
|
function copyFolderRecursiveSync(source, target, ignore) {
|
||||||
var files = [];
|
let files = [];
|
||||||
|
|
||||||
var base = path.basename(source);
|
let base = path.basename(source);
|
||||||
if (base === adapterName) {
|
if (base === adapterName) {
|
||||||
base = pkg.name;
|
base = pkg.name;
|
||||||
}
|
}
|
||||||
//check if folder needs to be created or integrated
|
//check if folder needs to be created or integrated
|
||||||
var targetFolder = path.join(target, base);
|
const targetFolder = path.join(target, base);
|
||||||
if (!fs.existsSync(targetFolder)) {
|
if (!fs.existsSync(targetFolder)) {
|
||||||
fs.mkdirSync(targetFolder);
|
fs.mkdirSync(targetFolder);
|
||||||
}
|
}
|
||||||
@@ -65,8 +84,8 @@ function copyFolderRecursiveSync(source, target, ignore) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var curSource = path.join(source, file);
|
const curSource = path.join(source, file);
|
||||||
var curTarget = path.join(targetFolder, file);
|
const curTarget = path.join(targetFolder, file);
|
||||||
if (fs.lstatSync(curSource).isDirectory()) {
|
if (fs.lstatSync(curSource).isDirectory()) {
|
||||||
// ignore grunt files
|
// ignore grunt files
|
||||||
if (file.indexOf('grunt') !== -1) return;
|
if (file.indexOf('grunt') !== -1) return;
|
||||||
@@ -84,12 +103,13 @@ if (!fs.existsSync(rootDir + 'tmp')) {
|
|||||||
fs.mkdirSync(rootDir + 'tmp');
|
fs.mkdirSync(rootDir + 'tmp');
|
||||||
}
|
}
|
||||||
|
|
||||||
function storeOriginalFiles() {
|
async function storeOriginalFiles() {
|
||||||
console.log('Store original files...');
|
console.log('Store original files...');
|
||||||
var dataDir = rootDir + 'tmp/' + appName + '-data/';
|
const dataDir = rootDir + 'tmp/' + appName + '-data/';
|
||||||
|
|
||||||
var f = fs.readFileSync(dataDir + 'objects.json');
|
if (fs.existsSync(dataDir + 'objects.json')) {
|
||||||
var objects = JSON.parse(f.toString());
|
const f = fs.readFileSync(dataDir + 'objects.json');
|
||||||
|
const objects = JSON.parse(f.toString());
|
||||||
if (objects['system.adapter.admin.0'] && objects['system.adapter.admin.0'].common) {
|
if (objects['system.adapter.admin.0'] && objects['system.adapter.admin.0'].common) {
|
||||||
objects['system.adapter.admin.0'].common.enabled = false;
|
objects['system.adapter.admin.0'].common.enabled = false;
|
||||||
}
|
}
|
||||||
@@ -98,40 +118,86 @@ function storeOriginalFiles() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fs.writeFileSync(dataDir + 'objects.json.original', JSON.stringify(objects));
|
fs.writeFileSync(dataDir + 'objects.json.original', JSON.stringify(objects));
|
||||||
try {
|
console.log('Store original objects.json');
|
||||||
f = fs.readFileSync(dataDir + 'states.json');
|
|
||||||
fs.writeFileSync(dataDir + 'states.json.original', f);
|
|
||||||
}
|
}
|
||||||
catch (err) {
|
|
||||||
|
if (fs.existsSync(dataDir + 'states.json')) {
|
||||||
|
try {
|
||||||
|
const f = fs.readFileSync(dataDir + 'states.json');
|
||||||
|
fs.writeFileSync(dataDir + 'states.json.original', f);
|
||||||
|
console.log('Store original states.json');
|
||||||
|
} catch (err) {
|
||||||
console.log('no states.json found - ignore');
|
console.log('no states.json found - ignore');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fs.existsSync(dataDir + 'objects.jsonl')) {
|
||||||
|
loadJSONLDB();
|
||||||
|
const db = new JSONLDB(dataDir + 'objects.jsonl');
|
||||||
|
await db.open();
|
||||||
|
|
||||||
|
const admin0 = db.get('system.adapter.admin.0');
|
||||||
|
if (admin0) {
|
||||||
|
if (admin0.common) {
|
||||||
|
admin0.common.enabled = false;
|
||||||
|
db.set('system.adapter.admin.0', admin0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const admin1 = db.get('system.adapter.admin.1');
|
||||||
|
if (admin1) {
|
||||||
|
if (admin1.common) {
|
||||||
|
admin1.common.enabled = false;
|
||||||
|
db.set('system.adapter.admin.1', admin1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await db.close();
|
||||||
|
|
||||||
|
const f = fs.readFileSync(dataDir + 'objects.jsonl');
|
||||||
|
fs.writeFileSync(dataDir + 'objects.jsonl.original', f);
|
||||||
|
console.log('Store original objects.jsonl');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fs.existsSync(dataDir + 'states.jsonl')) {
|
||||||
|
const f = fs.readFileSync(dataDir + 'states.jsonl');
|
||||||
|
fs.writeFileSync(dataDir + 'states.jsonl.original', f);
|
||||||
|
console.log('Store original states.jsonl');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function restoreOriginalFiles() {
|
function restoreOriginalFiles() {
|
||||||
console.log('restoreOriginalFiles...');
|
console.log('restoreOriginalFiles...');
|
||||||
var dataDir = rootDir + 'tmp/' + appName + '-data/';
|
const dataDir = rootDir + 'tmp/' + appName + '-data/';
|
||||||
|
|
||||||
var f = fs.readFileSync(dataDir + 'objects.json.original');
|
if (fs.existsSync(dataDir + 'objects.json.original')) {
|
||||||
|
const f = fs.readFileSync(dataDir + 'objects.json.original');
|
||||||
fs.writeFileSync(dataDir + 'objects.json', f);
|
fs.writeFileSync(dataDir + 'objects.json', f);
|
||||||
try {
|
}
|
||||||
f = fs.readFileSync(dataDir + 'states.json.original');
|
if (fs.existsSync(dataDir + 'objects.json.original')) {
|
||||||
|
const f = fs.readFileSync(dataDir + 'states.json.original');
|
||||||
fs.writeFileSync(dataDir + 'states.json', f);
|
fs.writeFileSync(dataDir + 'states.json', f);
|
||||||
}
|
}
|
||||||
catch (err) {
|
|
||||||
console.log('no states.json.original found - ignore');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (fs.existsSync(dataDir + 'objects.jsonl.original')) {
|
||||||
|
const f = fs.readFileSync(dataDir + 'objects.jsonl.original');
|
||||||
|
fs.writeFileSync(dataDir + 'objects.jsonl', f);
|
||||||
|
}
|
||||||
|
if (fs.existsSync(dataDir + 'objects.jsonl.original')) {
|
||||||
|
const f = fs.readFileSync(dataDir + 'states.jsonl.original');
|
||||||
|
fs.writeFileSync(dataDir + 'states.jsonl', f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkIsAdapterInstalled(cb, counter, customName) {
|
async function checkIsAdapterInstalled(cb, counter, customName) {
|
||||||
customName = customName || pkg.name.split('.').pop();
|
customName = customName || pkg.name.split('.').pop();
|
||||||
counter = counter || 0;
|
counter = counter || 0;
|
||||||
var dataDir = rootDir + 'tmp/' + appName + '-data/';
|
const dataDir = rootDir + 'tmp/' + appName + '-data/';
|
||||||
console.log('checkIsAdapterInstalled...');
|
console.log('checkIsAdapterInstalled...');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var f = fs.readFileSync(dataDir + 'objects.json');
|
if (fs.existsSync(dataDir + 'objects.json')) {
|
||||||
var objects = JSON.parse(f.toString());
|
const f = fs.readFileSync(dataDir + 'objects.json');
|
||||||
|
const objects = JSON.parse(f.toString());
|
||||||
if (objects['system.adapter.' + customName + '.0']) {
|
if (objects['system.adapter.' + customName + '.0']) {
|
||||||
console.log('checkIsAdapterInstalled: ready!');
|
console.log('checkIsAdapterInstalled: ready!');
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
@@ -141,8 +207,36 @@ function checkIsAdapterInstalled(cb, counter, customName) {
|
|||||||
} else {
|
} else {
|
||||||
console.warn('checkIsAdapterInstalled: still not ready');
|
console.warn('checkIsAdapterInstalled: still not ready');
|
||||||
}
|
}
|
||||||
|
} else if (fs.existsSync(dataDir + 'objects.jsonl')) {
|
||||||
|
loadJSONLDB();
|
||||||
|
const db = new JSONLDB(dataDir + 'objects.jsonl');
|
||||||
|
try {
|
||||||
|
await db.open();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
if (err.message.includes('Failed to lock DB file')) {
|
||||||
|
console.log('checkIsAdapterInstalled: DB still opened ...');
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
const obj = db.get('system.adapter.' + customName + '.0');
|
||||||
|
await db.close();
|
||||||
|
|
||||||
|
if (obj) {
|
||||||
|
console.log('checkIsAdapterInstalled: ready!');
|
||||||
|
setTimeout(function () {
|
||||||
|
if (cb) cb();
|
||||||
|
}, 100);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
console.warn('checkIsAdapterInstalled: still not ready');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.error('checkIsAdapterInstalled: No objects file found in datadir ' + dataDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.log('checkIsAdapterInstalled: catch ' + err);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (counter > 20) {
|
if (counter > 20) {
|
||||||
@@ -156,14 +250,15 @@ function checkIsAdapterInstalled(cb, counter, customName) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkIsControllerInstalled(cb, counter) {
|
async function checkIsControllerInstalled(cb, counter) {
|
||||||
counter = counter || 0;
|
counter = counter || 0;
|
||||||
var dataDir = rootDir + 'tmp/' + appName + '-data/';
|
const dataDir = rootDir + 'tmp/' + appName + '-data/';
|
||||||
|
|
||||||
console.log('checkIsControllerInstalled...');
|
console.log('checkIsControllerInstalled...');
|
||||||
try {
|
try {
|
||||||
var f = fs.readFileSync(dataDir + 'objects.json');
|
if (fs.existsSync(dataDir + 'objects.json')) {
|
||||||
var objects = JSON.parse(f.toString());
|
const f = fs.readFileSync(dataDir + 'objects.json');
|
||||||
|
const objects = JSON.parse(f.toString());
|
||||||
if (objects['system.certificates']) {
|
if (objects['system.certificates']) {
|
||||||
console.log('checkIsControllerInstalled: installed!');
|
console.log('checkIsControllerInstalled: installed!');
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
@@ -171,6 +266,32 @@ function checkIsControllerInstalled(cb, counter) {
|
|||||||
}, 100);
|
}, 100);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} else if (fs.existsSync(dataDir + 'objects.jsonl')) {
|
||||||
|
loadJSONLDB();
|
||||||
|
const db = new JSONLDB(dataDir + 'objects.jsonl');
|
||||||
|
try {
|
||||||
|
await db.open();
|
||||||
|
} catch (err) {
|
||||||
|
if (err.message.includes('Failed to lock DB file')) {
|
||||||
|
console.log('checkIsControllerInstalled: DB still opened ...');
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
const obj = db.get('system.certificates');
|
||||||
|
await db.close();
|
||||||
|
|
||||||
|
if (obj) {
|
||||||
|
console.log('checkIsControllerInstalled: installed!');
|
||||||
|
setTimeout(function () {
|
||||||
|
if (cb) cb();
|
||||||
|
}, 100);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
console.error('checkIsControllerInstalled: No objects file found in datadir ' + dataDir);
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -193,7 +314,7 @@ function installAdapter(customName, cb) {
|
|||||||
}
|
}
|
||||||
customName = customName || pkg.name.split('.').pop();
|
customName = customName || pkg.name.split('.').pop();
|
||||||
console.log('Install adapter...');
|
console.log('Install adapter...');
|
||||||
var startFile = 'node_modules/' + appName + '.js-controller/' + appName + '.js';
|
const startFile = 'node_modules/' + appName + '.js-controller/' + appName + '.js';
|
||||||
// make first install
|
// make first install
|
||||||
if (debug) {
|
if (debug) {
|
||||||
child_process.execSync('node ' + startFile + ' add ' + customName + ' --enabled false', {
|
child_process.execSync('node ' + startFile + ' add ' + customName + ' --enabled false', {
|
||||||
@@ -207,7 +328,7 @@ function installAdapter(customName, cb) {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// add controller
|
// add controller
|
||||||
var _pid = child_process.fork(startFile, ['add', customName, '--enabled', 'false'], {
|
const _pid = child_process.fork(startFile, ['add', customName, '--enabled', 'false'], {
|
||||||
cwd: rootDir + 'tmp',
|
cwd: rootDir + 'tmp',
|
||||||
stdio: [0, 1, 2, 'ipc']
|
stdio: [0, 1, 2, 'ipc']
|
||||||
});
|
});
|
||||||
@@ -252,7 +373,7 @@ function installJsController(cb) {
|
|||||||
// copy all
|
// copy all
|
||||||
// stop controller
|
// stop controller
|
||||||
console.log('Stop controller if running...');
|
console.log('Stop controller if running...');
|
||||||
var _pid;
|
let _pid;
|
||||||
if (debug) {
|
if (debug) {
|
||||||
// start controller
|
// start controller
|
||||||
_pid = child_process.exec('node ' + appName + '.js stop', {
|
_pid = child_process.exec('node ' + appName + '.js stop', {
|
||||||
@@ -277,7 +398,7 @@ function installJsController(cb) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
console.log('Setup js-controller...');
|
console.log('Setup js-controller...');
|
||||||
var __pid;
|
let __pid;
|
||||||
if (debug) {
|
if (debug) {
|
||||||
// start controller
|
// start controller
|
||||||
_pid = child_process.exec('node ' + appName + '.js setup first --console', {
|
_pid = child_process.exec('node ' + appName + '.js setup first --console', {
|
||||||
@@ -293,16 +414,20 @@ function installJsController(cb) {
|
|||||||
waitForEnd(__pid, function () {
|
waitForEnd(__pid, function () {
|
||||||
checkIsControllerInstalled(function () {
|
checkIsControllerInstalled(function () {
|
||||||
// change ports for object and state DBs
|
// change ports for object and state DBs
|
||||||
var config = require(rootDir + 'tmp/' + appName + '-data/' + appName + '.json');
|
const config = require(rootDir + 'tmp/' + appName + '-data/' + appName + '.json');
|
||||||
config.objects.port = 19001;
|
config.objects.port = 19001;
|
||||||
config.states.port = 19000;
|
config.states.port = 19000;
|
||||||
|
|
||||||
|
// TEST WISE!
|
||||||
|
//config.objects.type = 'jsonl';
|
||||||
|
//config.states.type = 'jsonl';
|
||||||
fs.writeFileSync(rootDir + 'tmp/' + appName + '-data/' + appName + '.json', JSON.stringify(config, null, 2));
|
fs.writeFileSync(rootDir + 'tmp/' + appName + '-data/' + appName + '.json', JSON.stringify(config, null, 2));
|
||||||
console.log('Setup finished.');
|
console.log('Setup finished.');
|
||||||
|
|
||||||
copyAdapterToController();
|
copyAdapterToController();
|
||||||
|
|
||||||
installAdapter(function () {
|
installAdapter(async function () {
|
||||||
storeOriginalFiles();
|
await storeOriginalFiles();
|
||||||
if (cb) cb(true);
|
if (cb) cb(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -310,7 +435,7 @@ function installJsController(cb) {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// check if port 9000 is free, else admin adapter will be added to running instance
|
// check if port 9000 is free, else admin adapter will be added to running instance
|
||||||
var client = new require('net').Socket();
|
const client = new require('net').Socket();
|
||||||
client.on('error', () => {});
|
client.on('error', () => {});
|
||||||
client.connect(9000, '127.0.0.1', function() {
|
client.connect(9000, '127.0.0.1', function() {
|
||||||
console.error('Cannot initiate fisrt run of test, because one instance of application is running on this PC. Stop it and repeat.');
|
console.error('Cannot initiate fisrt run of test, because one instance of application is running on this PC. Stop it and repeat.');
|
||||||
@@ -320,15 +445,15 @@ function installJsController(cb) {
|
|||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
client.destroy();
|
client.destroy();
|
||||||
if (!fs.existsSync(rootDir + 'tmp/node_modules/' + appName + '.js-controller')) {
|
if (!fs.existsSync(rootDir + 'tmp/node_modules/' + appName + '.js-controller')) {
|
||||||
console.log('installJsController: no js-controller => install from git');
|
console.log('installJsController: no js-controller => install dev build from npm');
|
||||||
|
|
||||||
child_process.execSync('npm install https://github.com/' + appName + '/' + appName + '.js-controller/tarball/master --prefix ./ --production', {
|
child_process.execSync('npm install ' + appName + '.js-controller@dev --prefix ./ --production', {
|
||||||
cwd: rootDir + 'tmp/',
|
cwd: rootDir + 'tmp/',
|
||||||
stdio: [0, 1, 2]
|
stdio: [0, 1, 2]
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
console.log('Setup js-controller...');
|
console.log('Setup js-controller...');
|
||||||
var __pid;
|
let __pid;
|
||||||
if (debug) {
|
if (debug) {
|
||||||
// start controller
|
// start controller
|
||||||
child_process.exec('node ' + appName + '.js setup first', {
|
child_process.exec('node ' + appName + '.js setup first', {
|
||||||
@@ -345,7 +470,7 @@ function installJsController(cb) {
|
|||||||
|
|
||||||
// let npm install admin and run setup
|
// let npm install admin and run setup
|
||||||
checkIsControllerInstalled(function () {
|
checkIsControllerInstalled(function () {
|
||||||
var _pid;
|
let _pid;
|
||||||
|
|
||||||
if (fs.existsSync(rootDir + 'node_modules/' + appName + '.js-controller/' + appName + '.js')) {
|
if (fs.existsSync(rootDir + 'node_modules/' + appName + '.js-controller/' + appName + '.js')) {
|
||||||
_pid = child_process.fork(appName + '.js', ['stop'], {
|
_pid = child_process.fork(appName + '.js', ['stop'], {
|
||||||
@@ -356,15 +481,19 @@ function installJsController(cb) {
|
|||||||
|
|
||||||
waitForEnd(_pid, function () {
|
waitForEnd(_pid, function () {
|
||||||
// change ports for object and state DBs
|
// change ports for object and state DBs
|
||||||
var config = require(rootDir + 'tmp/' + appName + '-data/' + appName + '.json');
|
const config = require(rootDir + 'tmp/' + appName + '-data/' + appName + '.json');
|
||||||
config.objects.port = 19001;
|
config.objects.port = 19001;
|
||||||
config.states.port = 19000;
|
config.states.port = 19000;
|
||||||
|
|
||||||
|
// TEST WISE!
|
||||||
|
//config.objects.type = 'jsonl';
|
||||||
|
//config.states.type = 'jsonl';
|
||||||
fs.writeFileSync(rootDir + 'tmp/' + appName + '-data/' + appName + '.json', JSON.stringify(config, null, 2));
|
fs.writeFileSync(rootDir + 'tmp/' + appName + '-data/' + appName + '.json', JSON.stringify(config, null, 2));
|
||||||
|
|
||||||
copyAdapterToController();
|
copyAdapterToController();
|
||||||
|
|
||||||
installAdapter(function () {
|
installAdapter(async function () {
|
||||||
storeOriginalFiles();
|
await storeOriginalFiles();
|
||||||
if (cb) cb(true);
|
if (cb) cb(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -387,8 +516,8 @@ function copyAdapterToController() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function clearControllerLog() {
|
function clearControllerLog() {
|
||||||
var dirPath = rootDir + 'tmp/log';
|
const dirPath = rootDir + 'tmp/log';
|
||||||
var files;
|
let files;
|
||||||
try {
|
try {
|
||||||
if (fs.existsSync(dirPath)) {
|
if (fs.existsSync(dirPath)) {
|
||||||
console.log('Clear controller log...');
|
console.log('Clear controller log...');
|
||||||
@@ -404,8 +533,8 @@ function clearControllerLog() {
|
|||||||
}
|
}
|
||||||
if (files.length > 0) {
|
if (files.length > 0) {
|
||||||
try {
|
try {
|
||||||
for (var i = 0; i < files.length; i++) {
|
for (let i = 0; i < files.length; i++) {
|
||||||
var filePath = dirPath + '/' + files[i];
|
const filePath = dirPath + '/' + files[i];
|
||||||
fs.unlinkSync(filePath);
|
fs.unlinkSync(filePath);
|
||||||
}
|
}
|
||||||
console.log('Controller log cleared');
|
console.log('Controller log cleared');
|
||||||
@@ -416,8 +545,8 @@ function clearControllerLog() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function clearDB() {
|
function clearDB() {
|
||||||
var dirPath = rootDir + 'tmp/iobroker-data/sqlite';
|
const dirPath = rootDir + 'tmp/iobroker-data/sqlite';
|
||||||
var files;
|
let files;
|
||||||
try {
|
try {
|
||||||
if (fs.existsSync(dirPath)) {
|
if (fs.existsSync(dirPath)) {
|
||||||
console.log('Clear sqlite DB...');
|
console.log('Clear sqlite DB...');
|
||||||
@@ -433,8 +562,8 @@ function clearDB() {
|
|||||||
}
|
}
|
||||||
if (files.length > 0) {
|
if (files.length > 0) {
|
||||||
try {
|
try {
|
||||||
for (var i = 0; i < files.length; i++) {
|
for (let i = 0; i < files.length; i++) {
|
||||||
var filePath = dirPath + '/' + files[i];
|
const filePath = dirPath + '/' + files[i];
|
||||||
fs.unlinkSync(filePath);
|
fs.unlinkSync(filePath);
|
||||||
}
|
}
|
||||||
console.log('Clear sqlite DB');
|
console.log('Clear sqlite DB');
|
||||||
@@ -445,7 +574,8 @@ function clearDB() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setupController(cb) {
|
function setupController(cb) {
|
||||||
installJsController(function (isInited) {
|
installJsController(async function (isInited) {
|
||||||
|
try {
|
||||||
clearControllerLog();
|
clearControllerLog();
|
||||||
clearDB();
|
clearDB();
|
||||||
|
|
||||||
@@ -454,14 +584,14 @@ function setupController(cb) {
|
|||||||
copyAdapterToController();
|
copyAdapterToController();
|
||||||
}
|
}
|
||||||
// read system.config object
|
// read system.config object
|
||||||
var dataDir = rootDir + 'tmp/' + appName + '-data/';
|
const dataDir = rootDir + 'tmp/' + appName + '-data/';
|
||||||
|
|
||||||
var objs;
|
if (fs.existsSync(dataDir + 'objects.json')) {
|
||||||
|
let objs;
|
||||||
try {
|
try {
|
||||||
objs = fs.readFileSync(dataDir + 'objects.json');
|
objs = fs.readFileSync(dataDir + 'objects.json');
|
||||||
objs = JSON.parse(objs);
|
objs = JSON.parse(objs);
|
||||||
}
|
} catch (e) {
|
||||||
catch (e) {
|
|
||||||
console.log('ERROR reading/parsing system configuration. Ignore');
|
console.log('ERROR reading/parsing system configuration. Ignore');
|
||||||
objs = {'system.config': {}};
|
objs = {'system.config': {}};
|
||||||
}
|
}
|
||||||
@@ -469,10 +599,74 @@ function setupController(cb) {
|
|||||||
objs = {'system.config': {}};
|
objs = {'system.config': {}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
systemConfig = objs['system.config'];
|
||||||
if (cb) cb(objs['system.config']);
|
if (cb) cb(objs['system.config']);
|
||||||
|
} else if (fs.existsSync(dataDir + 'objects.jsonl')) {
|
||||||
|
loadJSONLDB();
|
||||||
|
const db = new JSONLDB(dataDir + 'objects.jsonl');
|
||||||
|
await db.open();
|
||||||
|
|
||||||
|
let config = db.get('system.config');
|
||||||
|
systemConfig = config || {};
|
||||||
|
|
||||||
|
await db.close();
|
||||||
|
|
||||||
|
if (cb) cb(systemConfig);
|
||||||
|
} else {
|
||||||
|
console.error('read SystemConfig: No objects file found in datadir ' + dataDir);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('setupController: ' + err);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getSecret() {
|
||||||
|
var dataDir = rootDir + 'tmp/' + appName + '-data/';
|
||||||
|
|
||||||
|
if (systemConfig) {
|
||||||
|
return systemConfig.native.secret;
|
||||||
|
}
|
||||||
|
if (fs.existsSync(dataDir + 'objects.json')) {
|
||||||
|
let objs;
|
||||||
|
try {
|
||||||
|
objs = fs.readFileSync(dataDir + 'objects.json');
|
||||||
|
objs = JSON.parse(objs);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
console.warn("Could not load secret. Reason: " + e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!objs || !objs['system.config']) {
|
||||||
|
objs = {'system.config': {}};
|
||||||
|
}
|
||||||
|
|
||||||
|
return objs['system.config'].native.secre;
|
||||||
|
} else if (fs.existsSync(dataDir + 'objects.jsonl')) {
|
||||||
|
loadJSONLDB();
|
||||||
|
const db = new JSONLDB(dataDir + 'objects.jsonl');
|
||||||
|
await db.open();
|
||||||
|
|
||||||
|
let config = db.get('system.config');
|
||||||
|
config = config || {};
|
||||||
|
|
||||||
|
await db.close();
|
||||||
|
|
||||||
|
return config.native.secret;
|
||||||
|
} else {
|
||||||
|
console.error('read secret: No objects file found in datadir ' + dataDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function encrypt (key, value) {
|
||||||
|
var result = '';
|
||||||
|
for (var i = 0; i < value.length; ++i) {
|
||||||
|
result += String.fromCharCode(key[i % key.length].charCodeAt(0) ^ value.charCodeAt(i));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
function startAdapter(objects, states, callback) {
|
function startAdapter(objects, states, callback) {
|
||||||
if (adapterStarted) {
|
if (adapterStarted) {
|
||||||
console.log('Adapter already started ...');
|
console.log('Adapter already started ...');
|
||||||
@@ -522,20 +716,28 @@ function startController(isStartAdapter, onObjectChange, onStateChange, callback
|
|||||||
console.error('Controller is already started!');
|
console.error('Controller is already started!');
|
||||||
} else {
|
} else {
|
||||||
console.log('startController...');
|
console.log('startController...');
|
||||||
adapterStarted = false;
|
try {
|
||||||
var isObjectConnected;
|
const config = require(rootDir + 'tmp/' + appName + '-data/' + appName + '.json');
|
||||||
var isStatesConnected;
|
|
||||||
|
|
||||||
var Objects = require(rootDir + 'tmp/node_modules/' + appName + '.js-controller/lib/objects/objectsInMemServer');
|
adapterStarted = false;
|
||||||
|
let isObjectConnected;
|
||||||
|
let isStatesConnected;
|
||||||
|
|
||||||
|
// rootDir + 'tmp/node_modules
|
||||||
|
const objPath = require.resolve(`@iobroker/db-objects-${config.objects.type}`, {
|
||||||
|
paths: [ rootDir + 'tmp/node_modules', rootDir, rootDir + 'tmp/node_modules/' + appName + '.js-controller']
|
||||||
|
});
|
||||||
|
console.log('Objects Path: ' + objPath);
|
||||||
|
const Objects = require(objPath).Server;
|
||||||
objects = new Objects({
|
objects = new Objects({
|
||||||
connection: {
|
connection: {
|
||||||
"type" : "file",
|
'type': config.objects.type,
|
||||||
"host" : "127.0.0.1",
|
'host': '127.0.0.1',
|
||||||
"port" : 19001,
|
'port': 19001,
|
||||||
"user" : "",
|
'user': '',
|
||||||
"pass" : "",
|
'pass': '',
|
||||||
"noFileCache": false,
|
'noFileCache': false,
|
||||||
"connectTimeout": 2000
|
'connectTimeout': 2000
|
||||||
},
|
},
|
||||||
logger: {
|
logger: {
|
||||||
silly: function (msg) {
|
silly: function (msg) {
|
||||||
@@ -572,10 +774,14 @@ function startController(isStartAdapter, onObjectChange, onStateChange, callback
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Just open in memory DB itself
|
// Just open in memory DB itself
|
||||||
var States = require(rootDir + 'tmp/node_modules/' + appName + '.js-controller/lib/states/statesInMemServer');
|
const statePath = require.resolve(`@iobroker/db-states-${config.states.type}`, {
|
||||||
|
paths: [ rootDir + 'tmp/node_modules', rootDir, rootDir + 'tmp/node_modules/' + appName + '.js-controller']
|
||||||
|
});
|
||||||
|
console.log('States Path: ' + statePath);
|
||||||
|
const States = require(statePath).Server;
|
||||||
states = new States({
|
states = new States({
|
||||||
connection: {
|
connection: {
|
||||||
type: 'file',
|
type: config.states.type,
|
||||||
host: '127.0.0.1',
|
host: '127.0.0.1',
|
||||||
port: 19000,
|
port: 19000,
|
||||||
options: {
|
options: {
|
||||||
@@ -616,6 +822,9 @@ function startController(isStartAdapter, onObjectChange, onStateChange, callback
|
|||||||
},
|
},
|
||||||
change: onStateChange
|
change: onStateChange
|
||||||
});
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -660,7 +869,7 @@ function _stopController() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function stopController(cb) {
|
function stopController(cb) {
|
||||||
var timeout;
|
let timeout;
|
||||||
if (objects) {
|
if (objects) {
|
||||||
console.log('Set system.adapter.' + pkg.name + '.0');
|
console.log('Set system.adapter.' + pkg.name + '.0');
|
||||||
objects.setObject('system.adapter.' + pkg.name + '.0', {
|
objects.setObject('system.adapter.' + pkg.name + '.0', {
|
||||||
@@ -699,19 +908,47 @@ function stopController(cb) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setup the adapter
|
// Setup the adapter
|
||||||
function setAdapterConfig(common, native, instance) {
|
async function setAdapterConfig(common, native, instance) {
|
||||||
var objects = JSON.parse(fs.readFileSync(rootDir + 'tmp/' + appName + '-data/objects.json').toString());
|
const id = 'system.adapter.' + adapterName.split('.').pop() + '.' + (instance || 0);
|
||||||
var id = 'system.adapter.' + adapterName.split('.').pop() + '.' + (instance || 0);
|
if (fs.existsSync(rootDir + 'tmp/' + appName + '-data/objects.json')) {
|
||||||
|
const objects = JSON.parse(fs.readFileSync(rootDir + 'tmp/' + appName + '-data/objects.json').toString());
|
||||||
if (common) objects[id].common = common;
|
if (common) objects[id].common = common;
|
||||||
if (native) objects[id].native = native;
|
if (native) objects[id].native = native;
|
||||||
fs.writeFileSync(rootDir + 'tmp/' + appName + '-data/objects.json', JSON.stringify(objects));
|
fs.writeFileSync(rootDir + 'tmp/' + appName + '-data/objects.json', JSON.stringify(objects));
|
||||||
|
} else if (fs.existsSync(rootDir + 'tmp/' + appName + '-data/objects.jsonl')) {
|
||||||
|
loadJSONLDB();
|
||||||
|
const db = new JSONLDB(rootDir + 'tmp/' + appName + '-data/objects.jsonl');
|
||||||
|
await db.open();
|
||||||
|
|
||||||
|
let obj = db.get(id);
|
||||||
|
if (common) obj.common = common;
|
||||||
|
if (native) obj.native = native;
|
||||||
|
db.set(id, obj);
|
||||||
|
|
||||||
|
await db.close();
|
||||||
|
} else {
|
||||||
|
console.error('setAdapterConfig: No objects file found in datadir ' + rootDir + 'tmp/' + appName + '-data/');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read config of the adapter
|
// Read config of the adapter
|
||||||
function getAdapterConfig(instance) {
|
async function getAdapterConfig(instance) {
|
||||||
var objects = JSON.parse(fs.readFileSync(rootDir + 'tmp/' + appName + '-data/objects.json').toString());
|
const id = 'system.adapter.' + adapterName.split('.').pop() + '.' + (instance || 0);
|
||||||
var id = 'system.adapter.' + adapterName.split('.').pop() + '.' + (instance || 0);
|
if (fs.existsSync(rootDir + 'tmp/' + appName + '-data/objects.json')) {
|
||||||
|
const objects = JSON.parse(fs.readFileSync(rootDir + 'tmp/' + appName + '-data/objects.json').toString());
|
||||||
return objects[id];
|
return objects[id];
|
||||||
|
} else if (fs.existsSync(rootDir + 'tmp/' + appName + '-data/objects.jsonl')) {
|
||||||
|
loadJSONLDB();
|
||||||
|
const db = new JSONLDB(rootDir + 'tmp/' + appName + '-data/objects.jsonl');
|
||||||
|
await db.open();
|
||||||
|
|
||||||
|
let obj = db.get(id);
|
||||||
|
|
||||||
|
await db.close();
|
||||||
|
return obj;
|
||||||
|
} else {
|
||||||
|
console.error('getAdapterConfig: No objects file found in datadir ' + rootDir + 'tmp/' + appName + '-data/');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof module !== undefined && module.parent) {
|
if (typeof module !== undefined && module.parent) {
|
||||||
@@ -726,4 +963,6 @@ if (typeof module !== undefined && module.parent) {
|
|||||||
module.exports.appName = appName;
|
module.exports.appName = appName;
|
||||||
module.exports.adapterName = adapterName;
|
module.exports.adapterName = adapterName;
|
||||||
module.exports.adapterStarted = adapterStarted;
|
module.exports.adapterStarted = adapterStarted;
|
||||||
|
module.exports.getSecret = getSecret;
|
||||||
|
module.exports.encrypt = encrypt;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
process.on("unhandledRejection", (r) => { throw r; });
|
||||||
+3
-3
@@ -77,15 +77,15 @@ describe('Test ' + adapterShortName + ' adapter', function() {
|
|||||||
before('Test ' + adapterShortName + ' adapter: Start js-controller', function (_done) {
|
before('Test ' + adapterShortName + ' adapter: Start js-controller', function (_done) {
|
||||||
this.timeout(600000); // because of first install from npm
|
this.timeout(600000); // because of first install from npm
|
||||||
|
|
||||||
setup.setupController(function () {
|
setup.setupController(async function () {
|
||||||
var config = setup.getAdapterConfig();
|
var config = await setup.getAdapterConfig();
|
||||||
// enable adapter
|
// enable adapter
|
||||||
config.common.enabled = true;
|
config.common.enabled = true;
|
||||||
config.common.loglevel = 'debug';
|
config.common.loglevel = 'debug';
|
||||||
|
|
||||||
//config.native.dbtype = 'sqlite';
|
//config.native.dbtype = 'sqlite';
|
||||||
|
|
||||||
setup.setAdapterConfig(config.common, config.native);
|
await setup.setAdapterConfig(config.common, config.native);
|
||||||
|
|
||||||
setup.startController(true, function(id, obj) {}, function (id, state) {
|
setup.startController(true, function(id, obj) {}, function (id, state) {
|
||||||
if (onStateChanged) onStateChanged(id, state);
|
if (onStateChanged) onStateChanged(id, state);
|
||||||
|
|||||||
Reference in New Issue
Block a user