Initial commit
This commit is contained in:
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
node_modules
|
||||
.idea
|
||||
tmp
|
||||
admin/i18n/flat.txt
|
||||
admin/i18n/*/flat.txt
|
||||
iob_npm.done
|
||||
package-lock.json
|
||||
9
.npmignore
Normal file
9
.npmignore
Normal file
@@ -0,0 +1,9 @@
|
||||
gulpfile.js
|
||||
tasks
|
||||
tmp
|
||||
test
|
||||
.travis.yml
|
||||
appveyor.yml
|
||||
admin/i18n
|
||||
iob_npm.done
|
||||
package-lock.json
|
||||
34
.travis.yml
Normal file
34
.travis.yml
Normal file
@@ -0,0 +1,34 @@
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
language: node_js
|
||||
node_js:
|
||||
- '4'
|
||||
- '6'
|
||||
- '8'
|
||||
- '10'
|
||||
services:
|
||||
- mysql
|
||||
- postgresql
|
||||
before_install:
|
||||
- 'if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then export export CXX=g++-4.8; fi'
|
||||
before_script:
|
||||
- export NPMVERSION=$(echo "$($(which npm) -v)"|cut -c1)
|
||||
- 'if [[ $NPMVERSION == 5 ]]; then npm install -g npm@5; fi'
|
||||
- npm -v
|
||||
- 'if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi'
|
||||
- 'if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install mariadb && mysql.server start; fi'
|
||||
- 'if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then rm -rf /usr/local/var/postgres; fi'
|
||||
- 'if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then initdb /usr/local/var/postgres; fi'
|
||||
- 'if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then pg_ctl -D /usr/local/var/postgres start; fi'
|
||||
- 'if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then sleep 5; fi'
|
||||
- 'if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then createuser -s postgres; fi'
|
||||
- sleep 15
|
||||
- npm install winston@2.3.1
|
||||
- 'npm install https://git.spacen.net/yunkong2/yunkong2.js-controller/tarball/master --production'
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-4.8
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-2018 bluefox <dogafox@gmail.com>, Apollon77
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
506
README.md
Normal file
506
README.md
Normal file
@@ -0,0 +1,506 @@
|
||||

|
||||
# yunkong2.sql
|
||||
|
||||
==================================
|
||||
|
||||
[](https://www.npmjs.com/package/yunkong2.sql)
|
||||
[](https://www.npmjs.com/package/yunkong2.sql)
|
||||
[](https://travis-ci.org/yunkong2/yunkong2.sql)
|
||||
|
||||
[](https://nodei.co/npm/yunkong2.sql/)
|
||||
|
||||
This adapter saves state history into SQL DB.
|
||||
|
||||
Supports PostgreSQL, mysql, Microsoft SQL Server and sqlite.
|
||||
You can leave port 0 if default port is desired.
|
||||
|
||||
### MS-SQL:
|
||||
Use ```localhost\instance``` for host and check that TCP/IP connections are enabled.
|
||||
https://msdn.microsoft.com/en-us/library/bb909712(v=vs.90).aspx
|
||||
|
||||
### SQLite:
|
||||
is "file"-DB and cannot manage too many events. If you have a big amount of data use real DB, like PostgreSQL and co.
|
||||
|
||||
SQLite DB must not be installed extra. It is just a file on disk, but to install it you require build tools on your system. For linux, just write:
|
||||
|
||||
```
|
||||
sudo apt-get install build-essential
|
||||
```
|
||||
|
||||
For windows:
|
||||
|
||||
```
|
||||
c:\>npm install --global --production windows-build-tools
|
||||
```
|
||||
|
||||
And then reinstall the adapter, e.g:
|
||||
|
||||
```
|
||||
cd /opt/yunkong2
|
||||
yunkong2 stop sql
|
||||
npm install yunkong2.sql --production
|
||||
yunkong2 start sql
|
||||
```
|
||||
|
||||
### MySQL:
|
||||
You can install mysql on linux systems:
|
||||
|
||||
```
|
||||
apt-get install mysql-server mysql-client
|
||||
|
||||
mysql -uroot -p
|
||||
|
||||
CREATE USER 'yunkong2'@'%' IDENTIFIED BY 'yunkong2';
|
||||
GRANT ALL PRIVILEGES ON * . * TO 'yunkong2'@'%';
|
||||
FLUSH PRIVILEGES;
|
||||
```
|
||||
|
||||
If required edit */etc/mysql/my.cnf* to set bind to IP-Address for remote connect.
|
||||
|
||||
**Warning**: yunkong2 user is "admin". If required give limited rights to yunkong2 user.
|
||||
|
||||
## Structure of the DBs
|
||||
Default Database name is "yunkong2", but it can be changed in configuration.
|
||||
### Sources
|
||||
This table is a list of adapter's instances, that wrote the entries. (state.from)
|
||||
|
||||
| DB | Name in query |
|
||||
|------------|----------------------|
|
||||
| MS-SQL | yunkong2.dbo.sources |
|
||||
| MySQL | yunkong2.sources |
|
||||
| PostgreSQL | sources |
|
||||
| SQLite | sources |
|
||||
|
||||
Structure:
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|--------------------------------------------|-------------------------------------------|
|
||||
| id | INTEGER NOT NULL PRIMARY KEY IDENTITY(1,1) | unique ID |
|
||||
| name | varchar(255) / TEXT | instance of adapter, that wrote the entry |
|
||||
|
||||
*Note:* MS-SQL uses varchar(255), and others use TEXT
|
||||
|
||||
### Datapoints
|
||||
This table is a list of datapoints. (IDs)
|
||||
|
||||
| DB | Name in query |
|
||||
|------------|-------------------------|
|
||||
| MS-SQL | yunkong2.dbo.datapoints |
|
||||
| MySQL | yunkong2.datapoints |
|
||||
| PostgreSQL | datapoints |
|
||||
| SQLite | datapoints |
|
||||
|
||||
Structure:
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|--------------------------------------------|-------------------------------------------------|
|
||||
| id | INTEGER NOT NULL PRIMARY KEY IDENTITY(1,1) | unique ID |
|
||||
| name | varchar(255) / TEXT | ID of variable, e.g. hm-rpc.0.JEQ283747.1.STATE |
|
||||
| type | INTEGER | 0 - number, 1 - string, 2 - boolean |
|
||||
|
||||
*Note:* MS-SQL uses varchar(255), and others use TEXT
|
||||
|
||||
### Numbers
|
||||
Values for states with type "number". **ts** means "time series".
|
||||
|
||||
| DB | Name in query |
|
||||
|------------|-------------------------|
|
||||
| MS-SQL | yunkong2.dbo.ts_number |
|
||||
| MySQL | yunkong2.ts_number |
|
||||
| PostgreSQL | ts_number |
|
||||
| SQLite | ts_number |
|
||||
|
||||
Structure:
|
||||
|
||||
| Field | Type | Description |
|
||||
|--------|--------------------------------------------|-------------------------------------------------|
|
||||
| id | INTEGER | ID of state from "Datapoints" table |
|
||||
| ts | BIGINT / INTEGER | Time in ms till epoch. Can be converted to time with "new Date(ts)" |
|
||||
| val | REAL | Value |
|
||||
| ack | BIT/BOOLEAN | Is acknowledged: 0 - not ack, 1 - ack |
|
||||
| _from | INTEGER | ID of source from "Sources" table |
|
||||
| q | INTEGER | Quality as number. You can find description [here](https://git.spacen.net/yunkong2/yunkong2/blob/master/doc/SCHEMA.md#states) |
|
||||
|
||||
*Note:* MS-SQL uses BIT, and others use BOOLEAN. SQLite uses for ts INTEGER and all others BIGINT.
|
||||
|
||||
|
||||
### Strings
|
||||
Values for states with type "string".
|
||||
|
||||
| DB | Name in query |
|
||||
|------------|-------------------------|
|
||||
| MS-SQL | yunkong2.dbo.ts_string |
|
||||
| MySQL | yunkong2.ts_string |
|
||||
| PostgreSQL | ts_string |
|
||||
| SQLite | ts_string |
|
||||
|
||||
Structure:
|
||||
|
||||
| Field | Type | Description |
|
||||
|--------|--------------------------------------------|-------------------------------------------------|
|
||||
| id | INTEGER | ID of state from "Datapoints" table |
|
||||
| ts | BIGINT | Time in ms till epoch. Can be converted to time with "new Date(ts)" |
|
||||
| val | TEXT | Value |
|
||||
| ack | BIT/BOOLEAN | Is acknowledged: 0 - not ack, 1 - ack |
|
||||
| _from | INTEGER | ID of source from "Sources" table |
|
||||
| q | INTEGER | Quality as number. You can find description [here](https://git.spacen.net/yunkong2/yunkong2/blob/master/doc/SCHEMA.md#states) |
|
||||
|
||||
*Note:* MS-SQL uses BIT, and others use BOOLEAN. SQLite uses for ts INTEGER and all others BIGINT.
|
||||
|
||||
### Booleans
|
||||
Values for states with type "boolean".
|
||||
|
||||
| DB | Name in query |
|
||||
|------------|-------------------------|
|
||||
| MS-SQL | yunkong2.dbo.ts_bool |
|
||||
| MySQL | yunkong2.ts_bool |
|
||||
| PostgreSQL | ts_bool |
|
||||
| SQLite | ts_bool |
|
||||
|
||||
Structure:
|
||||
|
||||
| Field | Type | Description |
|
||||
|--------|--------------------------------------------|-------------------------------------------------|
|
||||
| id | INTEGER | ID of state from "Datapoints" table |
|
||||
| ts | BIGINT | Time in ms till epoch. Can be converted to time with "new Date(ts)" |
|
||||
| val | BIT/BOOLEAN | Value |
|
||||
| ack | BIT/BOOLEAN | Is acknowledged: 0 - not ack, 1 - ack |
|
||||
| _from | INTEGER | ID of source from "Sources" table |
|
||||
| q | INTEGER | Quality as number. You can find description [here](https://git.spacen.net/yunkong2/yunkong2/blob/master/doc/SCHEMA.md#states) |
|
||||
|
||||
*Note:* MS-SQL uses BIT, and others use BOOLEAN. SQLite uses for ts INTEGER and all others BIGINT.
|
||||
|
||||
## Custom queries
|
||||
The user can execute custom queries on tables from javascript adapter:
|
||||
|
||||
```
|
||||
sendTo('sql.0', 'query', 'SELECT * FROM datapoints', function (result) {
|
||||
if (result.error) {
|
||||
console.error(result.error);
|
||||
} else {
|
||||
// show result
|
||||
console.log('Rows: ' + JSON.stringify(result.result));
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
Or get entries for the last hour for ID=system.adapter.admin.0.memRss
|
||||
```
|
||||
sendTo('sql.0', 'query', 'SELECT id FROM datapoints WHERE name="system.adapter.admin.0.memRss"', function (result) {
|
||||
if (result.error) {
|
||||
console.error(result.error);
|
||||
} else {
|
||||
// show result
|
||||
console.log('Rows: ' + JSON.stringify(result.result));
|
||||
var now = new Date();
|
||||
now.setHours(-1);
|
||||
sendTo('sql.0', 'query', 'SELECT * FROM ts_number WHERE ts >= ' + now.getTime() + ' AND id=' + result.result[0].id, function (result) {
|
||||
console.log('Rows: ' + JSON.stringify(result.result));
|
||||
});
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## storeState
|
||||
If you want to write other data into the InfluxDB you can use the build in system function **storeState**.
|
||||
This function can also be used to convert data from other History adapters like History or SQL.
|
||||
|
||||
The given ids are not checked against the yunkong2 database and do not need to be set up there, but can only be accessed directly.
|
||||
|
||||
The Message can have one of the following three formats:
|
||||
* one ID and one state object
|
||||
* one ID and array of state objects
|
||||
* array of multiple IDs with state objects
|
||||
|
||||
## Get history
|
||||
Additional to custom queries, you can use build in system function **getHistory**:
|
||||
```
|
||||
var end = new Date().getTime();
|
||||
sendTo('sql.0', 'getHistory', {
|
||||
id: 'system.adapter.admin.0.memRss',
|
||||
options: {
|
||||
start: end - 3600000,
|
||||
end: end,
|
||||
aggregate: 'minmax' // or 'none' to get raw values
|
||||
}
|
||||
}, function (result) {
|
||||
for (var i = 0; i < result.result.length; i++) {
|
||||
console.log(result.result[i].id + ' ' + new Date(result.result[i].ts).toISOString());
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## History Logging Management via Javascript
|
||||
The adapter supports enabling and disabling of history logging via JavaScript and also retrieving the list of enabled datapoints with their settings.
|
||||
|
||||
### enable
|
||||
The message requires to have the "id" of the datapoint.Additionally optional "options" to define the datapoint specific settings:
|
||||
|
||||
```
|
||||
sendTo('sql.0', 'enableHistory', {
|
||||
id: 'system.adapter.sql.0.memRss',
|
||||
options: {
|
||||
changesOnly: true,
|
||||
debounce: 0,
|
||||
retention: 31536000,
|
||||
maxLength: 3,
|
||||
changesMinDelta: 0.5,
|
||||
aliasId: ""
|
||||
}
|
||||
}, function (result) {
|
||||
if (result.error) {
|
||||
console.log(result.error);
|
||||
}
|
||||
if (result.success) {
|
||||
//successfull enabled
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### disable
|
||||
The message requires to have the "id" of the datapoint.
|
||||
|
||||
```
|
||||
sendTo('sql.0', 'disableHistory', {
|
||||
id: 'system.adapter.sql.0.memRss',
|
||||
}, function (result) {
|
||||
if (result.error) {
|
||||
console.log(result.error);
|
||||
}
|
||||
if (result.success) {
|
||||
//successfull enabled
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### get List
|
||||
The message has no parameters.
|
||||
|
||||
```
|
||||
sendTo('sql.0', 'getEnabledDPs', {}, function (result) {
|
||||
//result is object like:
|
||||
{
|
||||
"system.adapter.sql.0.memRss": {
|
||||
"changesOnly":true,
|
||||
"debounce":0,
|
||||
"retention":31536000,
|
||||
"maxLength":3,
|
||||
"changesMinDelta":0.5,
|
||||
"enabled":true,
|
||||
"changesRelogInterval":0,
|
||||
"aliasId": ""
|
||||
}
|
||||
...
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Connection Settings
|
||||
- **DB Type**: Type of the SQL DB: MySQL, PostgreSQL, MS-SQL or SQLite3
|
||||
- **Host**: IP address or host name with SQL Server
|
||||
- **Port**: Port of SQL Server (leave blank if not sure)
|
||||
- **Database name**: Database name. Default yunkong2
|
||||
- **User**: User name for SQL. Must exists in the DB.
|
||||
- **Password**: Password for SQL.
|
||||
- **Password confirm**: Just repeat password here.
|
||||
- **Encrypt**: Some DBs support encryption.
|
||||
- **Round real to**: Number of digits after comma.
|
||||
- **Allow parallel requests**: Allow simultaneous SQL requests to DB.
|
||||
|
||||
## Default Settings
|
||||
- **De-bounce interval**: Do not store values often than this interval.
|
||||
- **Log unchanged values any**: Write additionally the values every X seconds.
|
||||
- **Minimum difference from last value to log**: Minimum interval between two values.
|
||||
- **Storage retention**: How long the values will be stored in DB.
|
||||
|
||||
## Changelog
|
||||
|
||||
## 1.9.0 (2018-06-19)
|
||||
* (Apollon77) Add option to log datapoints as other ID (alias) to easier migrate devices and such
|
||||
|
||||
## 1.8.0 (2018-04-29)
|
||||
* (Apollon77) Update sqlite3, nodejs 10 compatible
|
||||
* (BuZZy1337) Admin fix
|
||||
|
||||
## 1.7.4 (2018-04-15)
|
||||
* (Apollon77) Fix getHistory
|
||||
|
||||
## 1.7.3 (2018-03-28)
|
||||
* (Apollon77) Respect 'keep forever' setting for retention from datapoint configuration
|
||||
|
||||
## 1.7.2 (2018-03-24)
|
||||
* (Apollon77) Disable to write NULLs for SQLite
|
||||
|
||||
## 1.7.1 (2018-02-10)
|
||||
* (Apollon77) Make option to write NULL values on start/stop boundaries configurable
|
||||
|
||||
## 1.6.9 (2018-02-07)
|
||||
* (bondrogeen) Admin3 Fixes
|
||||
* (Apollon77) optimize relog feature and other things
|
||||
|
||||
## 1.6.7 (2018-01-31)
|
||||
* (Bluefox) Admin3 Fixes
|
||||
* (Apollon77) Relog and null log fixes
|
||||
|
||||
## 1.6.2 (2018-01-30)
|
||||
* (Apollon77) Admin3 Fixes
|
||||
|
||||
## 1.6.0 (2018-01-14)
|
||||
* (bluefox) Ready for Admin3
|
||||
|
||||
## 1.5.8 (2017-10-05)
|
||||
* (Apollon77) fix relog value feature
|
||||
|
||||
## 1.5.7 (2017-08-10)
|
||||
* (bluefox) add "save last value" option
|
||||
|
||||
## 1.5.6 (2017-08-02)
|
||||
* (Apollon77) fix behaviour of log interval to always log the current value
|
||||
|
||||
## 1.5.4 (2017-06-12)
|
||||
* (Apollon77) fix dependency to other library
|
||||
|
||||
## 1.5.3 (2017-04-07)
|
||||
* (Apollon77) fix in datatype conversions
|
||||
|
||||
### 1.5.0 (2017-03-02)
|
||||
* (Apollon77) Add option to define storage datatype per datapoint inclusing converting the value if needed
|
||||
|
||||
### 1.4.6 (2017-02-25)
|
||||
* (Apollon77) Fix typo with PostgrSQL
|
||||
|
||||
### 1.4.5 (2017-02-18)
|
||||
* (Apollon77) Small fix again for older configurations
|
||||
* (Apollon77) fix for DBConverter Analyze function
|
||||
|
||||
### 1.4.3 (2017-02-11)
|
||||
* (Apollon77) Small fix for older configurations
|
||||
|
||||
### 1.4.2 (2017-01-16)
|
||||
* (bluefox) Fix handling of float values in Adapter config and Datapoint config.
|
||||
|
||||
### 1.4.1
|
||||
* (Apollon77) Rollback to sql-client 0.7 to get rid of the mmagic dependecy that brings problems on older systems
|
||||
|
||||
### 1.4.0 (2016-12-02)
|
||||
* (Apollon77) Add messages enableHistory/disableHistory
|
||||
* (Apollon77) add support to log changes only if value differs a minimum value for numbers
|
||||
|
||||
### 1.3.4 (2016-11)
|
||||
* (Apollon77) Allow database names with '-' for MySQL
|
||||
|
||||
### 1.3.3 (2016-11)
|
||||
* (Apollon77) Update dependecies
|
||||
|
||||
### 1.3.2 (2016-11-21)
|
||||
* (bluefox) Fix insert of string with '
|
||||
|
||||
### 1.3.0 (2016-10-29)
|
||||
* (Apollon77) add option to re-log unchanged values to make it easier for visualization
|
||||
|
||||
### 1.2.1 (2016-08-30)
|
||||
* (bluefox) Fix selector for SQL objects
|
||||
|
||||
### 1.2.0 (2016-08-30)
|
||||
* (bluefox) сompatible only with new admin
|
||||
|
||||
### 1.0.10 (2016-08-27)
|
||||
* (bluefox) change name of object from "history" to "custom"
|
||||
|
||||
### 1.0.10 (2016-07-31)
|
||||
* (bluefox) fix multi requests if sqlite
|
||||
|
||||
### 1.0.9 (2016-06-14)
|
||||
* (bluefox) allow settings for parallel requests
|
||||
|
||||
### 1.0.7 (2016-05-31)
|
||||
* (bluefox) draw line to the end if ignore null
|
||||
|
||||
### 1.0.6 (2016-05-30)
|
||||
* (bluefox) allow setup DB name for mysql and mssql
|
||||
|
||||
### 1.0.5 (2016-05-29)
|
||||
* (bluefox) switch max and min with each other
|
||||
|
||||
### 1.0.4 (2016-05-29)
|
||||
* (bluefox) check retention of data if set "never"
|
||||
|
||||
### 1.0.3 (2016-05-28)
|
||||
* (bluefox) try to calculate old timestamps
|
||||
|
||||
### 1.0.2 (2016-05-24)
|
||||
* (bluefox) fix error with io-package
|
||||
|
||||
### 1.0.1 (2016-05-24)
|
||||
* (bluefox) fix error with SQLite
|
||||
|
||||
### 1.0.0 (2016-05-20)
|
||||
* (bluefox) change default aggregation name
|
||||
|
||||
### 0.3.3 (2016-05-18)
|
||||
* (bluefox) fix postgres
|
||||
|
||||
### 0.3.2 (2016-05-13)
|
||||
* (bluefox) queue select if IDs and FROMs queries for sqlite
|
||||
|
||||
### 0.3.1 (2016-05-12)
|
||||
* (bluefox) queue delete queries too for sqlite
|
||||
|
||||
### 0.3.0 (2016-05-08)
|
||||
* (bluefox) support of custom queries
|
||||
* (bluefox) only one request simultaneously for sqlite
|
||||
* (bluefox) add tests (primitive and only sql)
|
||||
|
||||
### 0.2.0 (2016-04-30)
|
||||
* (bluefox) support of milliseconds
|
||||
* (bluefox) fix sqlite
|
||||
|
||||
### 0.1.4 (2016-04-25)
|
||||
* (bluefox) fix deletion of old entries
|
||||
|
||||
### 0.1.3 (2016-03-08)
|
||||
* (bluefox) do not print errors twice
|
||||
|
||||
### 0.1.2 (2015-12-22)
|
||||
* (bluefox) fix MS-SQL port settings
|
||||
|
||||
### 0.1.1 (2015-12-19)
|
||||
* (bluefox) fix error with double entries
|
||||
|
||||
### 0.1.0 (2015-12-14)
|
||||
* (bluefox) support of strings
|
||||
|
||||
### 0.0.3 (2015-12-06)
|
||||
* (smiling_Jack) Add demo Data ( todo: faster insert to db )
|
||||
* (smiling_Jack) change aggregation (now same as history Adapter)
|
||||
* (bluefox) bug fixing
|
||||
|
||||
### 0.0.2 (2015-12-06)
|
||||
* (bluefox) allow only 1 client for SQLite
|
||||
|
||||
### 0.0.1 (2015-11-19)
|
||||
* (bluefox) initial commit
|
||||
|
||||
## License
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-2018 bluefox <dogafox@gmail.com>, Apollon77
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
0
admin/.gitignore
vendored
Normal file
0
admin/.gitignore
vendored
Normal file
169
admin/custom.html
Normal file
169
admin/custom.html
Normal file
@@ -0,0 +1,169 @@
|
||||
<script type="text/x-yunkong2" data-template-name="sql">
|
||||
<div class="form-row">
|
||||
<table style="font-size: 12px">
|
||||
<tr>
|
||||
<td class="translate">enabled</td>
|
||||
<td><input type="checkbox" data-field="enabled" data-default="false"></td>
|
||||
<!-- this field is mandatory, just to find out if to include this settings or not -->
|
||||
<td style="width: 40px"> </td>
|
||||
<td class="translate">log changes only</td>
|
||||
<td><input type="checkbox" data-field="changesOnly" data-default="true"></td>
|
||||
<td class="translate">De-bounce interval(ms)</td>
|
||||
<td><input type="number" data-field="debounce" min="500" max="86400000" data-default="10000"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td class="translate">log changes interval(s)</td>
|
||||
<td><input type="number" data-field="changesRelogInterval" min="0" max="86400000" data-default="0"></td>
|
||||
<td class="translate">0 = disable</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td class="translate">log changes minimal delta</td>
|
||||
<td><input type="number" step="any" data-field="changesMinDelta" min="0" max="86400000" data-default="0"></td>
|
||||
<td class="translate">0 = disable delta check</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td class="translate">Store as</td>
|
||||
<td>
|
||||
<select data-field="storageType" data-default="">
|
||||
<option value="" class="translate">Automatic</option>
|
||||
<option value="String" class="translate">String</option>
|
||||
<option value="Number" class="translate">Number</option>
|
||||
<option value="Boolean" class="translate">Boolean</option>
|
||||
</select>
|
||||
</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td class="translate">Storage retention</td>
|
||||
<td>
|
||||
<select data-field="retention" data-default="31536000">
|
||||
<option value="0" class="translate">keep forever</option>
|
||||
<option value="63072000" class="translate">2 years</option>
|
||||
<option value="31536000" class="translate">1 year</option>
|
||||
<option value="15811200" class="translate">6 months</option>
|
||||
<option value="7948800" class="translate">3 months</option>
|
||||
<option value="2678400" class="translate">1 months</option>
|
||||
<option value="1209600" class="translate">2 weeks</option>
|
||||
<option value="604800" class="translate">1 week</option>
|
||||
<option value="432000" class="translate">5 days</option>
|
||||
<option value="259200" class="translate">3 days</option>
|
||||
<option value="86400" class="translate">1 day</option>
|
||||
</select>
|
||||
</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="translate">aliasId</td>
|
||||
<td colspan=2><input type="value" data-field="aliasId" data-default="" maxlength="30" style="width: 100px"></td>
|
||||
<td></td>
|
||||
<td colspan=3 class="translate">Alias Info</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<!-- translations -->
|
||||
<script type="text/javascript">
|
||||
systemDictionary = $.extend(systemDictionary, {
|
||||
"enabled": {"en": "enabled", "de": "Aktiviert", "ru": "активно"},
|
||||
"De-bounce interval(ms)": {"en": "De-bounce interval(ms)", "de": "Entprellzeit(ms)", "ru": "Минимальный интервал(ms)"},
|
||||
"log changes interval(s)": {
|
||||
"en": "Log unchanged values any(s)",
|
||||
"de": "Gleiche Werte aufzeichnen(s)",
|
||||
"ru": "Запись неизменённых значений каждые (сек)"
|
||||
},
|
||||
"log changes minimal delta": {
|
||||
"en": "Minimum difference from last value to log",
|
||||
"de": "Minimale Abweichung vom letzten Wert für Aufzeichnung",
|
||||
"ru": "Минимальная разница с последним записанным значением"
|
||||
},
|
||||
"0 = disable delta check": {
|
||||
"en": "0 = disable delta check",
|
||||
"de": "0 = Abweichungsprüfung deaktivieren",
|
||||
"ru": "0 = не проверять минимальное изменение"
|
||||
},
|
||||
"log changes only": {"en": "log by changes", "de": "Bei Änderungen aufzeichnen", "ru": "При изменениях"},
|
||||
"0 = disable": {
|
||||
"en": "0 = disable",
|
||||
"de": "0 = Deaktivieren",
|
||||
"ru": "0 = не активно"
|
||||
},
|
||||
"maximum datapoint count in RAM": {
|
||||
"en": "maximum datapoint count in RAM",
|
||||
"de": "maximale Anzahl Datenpunkte in RAM",
|
||||
"ru": "макс. кол-во значений в RAM памяти"
|
||||
},
|
||||
"Store as": {"en": "Store as", "de": "Speichern als", "ru": "Store as"},
|
||||
"Automatic": {"en": "Automatic", "de": "Automatisch", "ru": "Automatic"},
|
||||
"String": {"en": "String", "de": "String", "ru": "String"},
|
||||
"Number": {"en": "Number", "de": "Number", "ru": "Number"},
|
||||
"Boolean": {"en": "Boolean", "de": "Boolean", "ru": "Boolean"},
|
||||
"Storage retention": {"en": "Storage retention", "de": "Storage Vorhaltezeit", "ru": "Сохранять в базе файле"},
|
||||
"keep forever": {"en": "keep forever", "de": "keine automatische Löschung", "ru": "хранить вечно"},
|
||||
"2 years": {"en": "2 years", "de": "2 Jahre", "ru": "2 года"},
|
||||
"1 year": {"en": "1 year", "de": "1 Jahr", "ru": "1 год"},
|
||||
"6 months": {"en": "6 months", "de": "6 Monate", "ru": "6 месяцев"},
|
||||
"3 months": {"en": "3 months", "de": "3 Monate", "ru": "3 месяца"},
|
||||
"1 months": {"en": "1 months", "de": "1 Monat", "ru": "1 месяц"},
|
||||
"2 weeks": {"en": "2 weeks", "de": "2 Wochen", "ru": "2 недели"},
|
||||
"1 week": {"en": "1 week", "de": "1 Woche", "ru": "1 неделя"},
|
||||
"5 days": {"en": "5 days", "de": "5 Tage", "ru": "5 дней"},
|
||||
"3 days": {"en": "3 days", "de": "3 Tage", "ru": "3 дня"},
|
||||
"1 day": {"en": "1 day", "de": "1 Tag", "ru": "1 день"},
|
||||
"aliasId": {
|
||||
"en": "Alias-ID"
|
||||
},
|
||||
"Alias Info": {
|
||||
"en": "if not empty data will be logged as this ID in data files"
|
||||
}
|
||||
}
|
||||
);
|
||||
// There are two ways how to predefine default settings:
|
||||
// - with attribute "data-default" (content independent)
|
||||
// - with function in global variable "defaults". Function name is equal with adapter name.
|
||||
// as input function receives object with all information concerning it
|
||||
if (typeof defaults !== 'undefined') {
|
||||
defaults.sql = function (obj, instanceObj) {
|
||||
if (obj && obj.common && obj.common.type !== 'number') {
|
||||
return {
|
||||
enabled: false,
|
||||
changesOnly: false,
|
||||
debounce: 0,
|
||||
retention: instanceObj.native.retention,
|
||||
changesRelogInterval: instanceObj.native.changesRelogInterval,
|
||||
changesMinDelta: 0,
|
||||
storageType: '',
|
||||
aliasId: ''
|
||||
};
|
||||
}
|
||||
return {
|
||||
enabled: false,
|
||||
changesOnly: true,
|
||||
debounce: instanceObj.native.debounce,
|
||||
retention: instanceObj.native.retention,
|
||||
changesRelogInterval: instanceObj.native.changesRelogInterval,
|
||||
changesMinDelta: instanceObj.native.changesMinDelta,
|
||||
storageType: '',
|
||||
aliasId: ''
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
151
admin/custom_m.html
Normal file
151
admin/custom_m.html
Normal file
@@ -0,0 +1,151 @@
|
||||
<script type="text/x-yunkong2" data-template-name="sql">
|
||||
<div class="row">
|
||||
<div class="col s4">
|
||||
<input type="checkbox" data-field="enabled" data-default="false"/>
|
||||
<!-- this field is mandatory, just to find out if to include this settings or not</span-->
|
||||
<span class="translate">enabled</span>
|
||||
</div>
|
||||
<div class="col s4">
|
||||
<input type="checkbox" data-field="changesOnly" data-default="true"/>
|
||||
<span class="translate">log changes only</span>
|
||||
</div>
|
||||
<div class="col s4">
|
||||
<input type="number" data-field="debounce" min="500" max="86400000" data-default="10000" />
|
||||
<label class="translate">De-bounce interval(ms)</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col s4">
|
||||
</div>
|
||||
<div class="col s4">
|
||||
<input type="number" data-field="changesRelogInterval" min="0" max="86400000" data-default="0" />
|
||||
<label class="translate">log changes interval(s) (0 = disable)</label>
|
||||
</div>
|
||||
<div class="col s4">
|
||||
<input type="number" data-field="changesMinDelta" min="0" max="86400000" data-default="0" />
|
||||
<label class="translate">log changes minimal delta (0 = disable delta check)</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col s4">
|
||||
</div>
|
||||
<div class="col s4">
|
||||
<select data-field="storageType" data-default="">
|
||||
<option value="" class="translate">Automatic</option>
|
||||
<option value="String" class="translate">String</option>
|
||||
<option value="Number" class="translate">Number</option>
|
||||
<option value="Boolean" class="translate">Boolean</option>
|
||||
</select>
|
||||
<label class="translate">Store as</label>
|
||||
</div>
|
||||
<div class="col s4">
|
||||
<select data-field="retention" data-default="31536000">
|
||||
<option value="0" class="translate">keep forever</option>
|
||||
<option value="63072000" class="translate">2 years</option>
|
||||
<option value="31536000" class="translate">1 year</option>
|
||||
<option value="15811200" class="translate">6 months</option>
|
||||
<option value="7948800" class="translate">3 months</option>
|
||||
<option value="2678400" class="translate">1 months</option>
|
||||
<option value="1209600" class="translate">2 weeks</option>
|
||||
<option value="604800" class="translate">1 week</option>
|
||||
<option value="432000" class="translate">5 days</option>
|
||||
<option value="259200" class="translate">3 days</option>
|
||||
<option value="86400" class="translate">1 day</option>
|
||||
</select>
|
||||
<label class="translate">Storage retention</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col s8">
|
||||
<input class="value" data-field="aliasId" data-default="" type="text" maxlength="255" />
|
||||
<label class="translate">aliasId</label>
|
||||
</div>
|
||||
<div class="col s4">
|
||||
<label class="translate">Alias Info</label>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<!-- translations -->
|
||||
<script type="text/javascript">
|
||||
systemDictionary = $.extend(systemDictionary, {
|
||||
"1 day": { "en": "1 day", "de": "1 Tag", "ru": "1 день", "pt": "1 dia", "nl": "1 dag", "fr": "Un jour", "it": "1 giorno", "es": "1 día", "pl": "1 dzień"},
|
||||
"1 months": { "en": "1 months", "de": "1 Monat", "ru": "1 месяц", "pt": "1 mês", "nl": "1 maanden", "fr": "1 mois", "it": "1 mese", "es": "1 mes", "pl": "1 miesiąc"},
|
||||
"1 week": { "en": "1 week", "de": "1 Woche", "ru": "1 неделя", "pt": "1 semana", "nl": "1 week", "fr": "1 semaine", "it": "1 settimana", "es": "1 semana", "pl": "1 tydzień"},
|
||||
"1 year": { "en": "1 year", "de": "1 Jahr", "ru": "1 год", "pt": "1 ano", "nl": "1 jaar", "fr": "1 an", "it": "1 anno", "es": "1 año", "pl": "1 rok"},
|
||||
"2 weeks": { "en": "2 weeks", "de": "2 Wochen", "ru": "2 недели", "pt": "2 semanas", "nl": "2 weken", "fr": "2 semaines", "it": "2 settimane", "es": "2 semanas", "pl": "2 tygodnie"},
|
||||
"2 years": { "en": "2 years", "de": "2 Jahre", "ru": "2 года", "pt": "2 anos", "nl": "2 jaar", "fr": "2 ans", "it": "2 anni", "es": "2 años", "pl": "2 lata"},
|
||||
"3 days": { "en": "3 days", "de": "3 Tage", "ru": "3 дня", "pt": "3 dias", "nl": "3 dagen", "fr": "3 jours", "it": "3 giorni", "es": "3 días", "pl": "3 dni"},
|
||||
"3 months": { "en": "3 months", "de": "3 Monate", "ru": "3 месяца", "pt": "3 meses", "nl": "3 maanden", "fr": "3 mois", "it": "3 mesi", "es": "3 meses", "pl": "3 miesiące"},
|
||||
"5 days": { "en": "5 days", "de": "5 Tage", "ru": "5 дней", "pt": "5 dias", "nl": "5 dagen", "fr": "5 jours", "it": "5 giorni", "es": "5 dias", "pl": "5 dni"},
|
||||
"6 months": { "en": "6 months", "de": "6 Monate", "ru": "6 месяцев", "pt": "6 meses", "nl": "6 maanden", "fr": "6 mois", "it": "6 mesi", "es": "6 meses", "pl": "6 miesięcy"},
|
||||
"Store as": { "en": "Store as", "de": "Speichern als", "ru": "Сохранить как", "pt": "Armazenar como", "nl": "Opslaan als", "fr": "Magasin comme", "it": "Conservare come", "es": "Przechowuj jako", "pl": "Przechowuj jako"},
|
||||
"Automatic": { "en": "Automatic", "de": "Automatisch", "ru": "автоматическая", "pt": "Automático", "nl": "automatisch", "fr": "Automatique", "it": "Automatico", "es": "Automatycznyy", "pl": "Automatyczny"},
|
||||
"String": { "en": "String", "de": "Zeichenfolge", "ru": "строка", "pt": "Corda", "nl": "Draad", "fr": "Chaîne", "it": "Stringa", "es": "Strunowy", "pl": "Strunowy"},
|
||||
"Number": { "en": "Number", "de": "Nummer", "ru": "Число", "pt": "Número", "nl": "Aantal", "fr": "Nombre", "it": "Numero", "es": "Numer", "pl": "Numer"},
|
||||
"Boolean": { "en": "Boolean", "de": "Boolesch", "ru": "логический", "pt": "boleano", "nl": "Boolean", "fr": "Booléen", "it": "booleano", "es": "Booleano", "pl": "Boolean"},
|
||||
"De-bounce interval(ms)": { "en": "De-bounce interval(ms)", "de": "Entprellzeit(ms)", "ru": "Минимальный интервал(ms)", "pt": "Intervalo de desvio (ms)", "nl": "De-bounce interval (ms)", "fr": "Intervalle de rebond (ms)", "it": "Intervallo di rimbalzo (ms)", "es": "Intervalo de rebote (ms)", "pl": "Interwał odbicia (ms)"},
|
||||
"Storage retention": { "en": "Storage retention", "de": "Storage Vorhaltezeit", "ru": "Сохранять в файле", "pt": "Retenção de armazenamento", "nl": "Opslag retentie", "fr": "Conservation du stockage", "it": "Conservazione di memoria", "es": "Retención de almacenamiento", "pl": "Przechowywanie danych"},
|
||||
"enabled": { "en": "enabled", "de": "Aktiviert", "ru": "активно", "pt": "ativado", "nl": "ingeschakeld", "fr": "activée", "it": "abilitato", "es": "habilitado", "pl": "włączony"},
|
||||
"keep forever": { "en": "keep forever", "de": "keine automatische Löschung", "ru": "хранить вечно", "pt": "mantenha para sempre", "nl": "blijf voor altijd", "fr": "garde pour toujours", "it": "tienilo per sempre", "es": "mantener para siempre", "pl": "zachowaj na zawsze"},
|
||||
"log changes interval(s) (0 = disable)": { "en": "Log values any(s)<br>(0 = disable)", "de": "Nach Intervall aufzeichnen(s)<br>(0 = Deaktivieren)", "ru": "Запись значений каждые (сек)<br>(0 = не активно)", "pt": "Intervalo (s) de alterações no log (s)<br>(0 = desativado)", "nl": "log wijzigt interval (s)<br>(0 = uitschakelen)", "fr": "log changements intervalle (s)<br>(0 = désactiver)", "it": "log changes interval (s)<br>(0 = disabilita)", "es": "Log valores any (s) <br> (0 = desactivar)", "pl": "Wartości logów any (s) <br> (0 = wyłączone)"},
|
||||
"log changes minimal delta (0 = disable delta check)": {"en": "Minimum difference from last value to log<br>(0 = disable delta check)", "de": "Minimale Abweichung vom letzten Wert für Aufzeichnung<br>(0 = Abweichungsprüfung deaktivieren)", "ru": "Минимальная разница с последним записанным значением<br>(0 = не проверять минимальное изменение)", "pt": "log altera delta mínimo<br>(0 = desabilita o checkout delta)", "nl": "log veranderingen minimale delta<br>(0 = deltablokkering uitschakelen)", "fr": "log change delta minimal<br>(0 = désactiver le contrôle delta)", "it": "registro cambia delta minimo<br>(0 = disabilita il controllo delta)", "es": "Diferencia mínima entre el último valor y el log <br> (0 = desactivar la verificación delta)", "pl": "Minimalna różnica od ostatniej wartości do log <br> (0 = wyłącz kontrolę delta)"},
|
||||
"log changes only": { "en": "log changes only", "de": "Änderungen aufzeichnen", "ru": "Только изменения", "pt": "somente mudanças de log", "nl": "alleen logboekwijzigingen", "fr": "modifications du journal uniquement", "it": "registra solo le modifiche", "es": "solo cambios de registro", "pl": "tylko zmiany w dzienniku"},
|
||||
"maximum datapoint count in RAM": { "en": "maximum datapoint count in RAM", "de": "maximale Anzahl Datenpunkte in RAM", "ru": "макс. кол-во значений в RAM памяти", "pt": "contagem máxima do datapoint na RAM", "nl": "maximum aantal datapunten in RAM", "fr": "nombre de points de données maximum en RAM", "it": "massimo conteggio dei punti di accesso nella RAM", "es": "recuento máximo de datos en RAM", "pl": "maksymalna liczba punktów w pamięci RAM"},
|
||||
"aliasId": {
|
||||
"en": "Alias-ID",
|
||||
"de": "Alias-ID",
|
||||
"ru": "Псевдоним ИД",
|
||||
"pt": "Alias-ID",
|
||||
"nl": "Alias-ID",
|
||||
"fr": "Alias-ID",
|
||||
"it": "Alias-ID",
|
||||
"es": "Alias-ID",
|
||||
"pl": "Alias-ID"
|
||||
},
|
||||
"Alias Info": {
|
||||
"en": "if Alias-ID is set, the data will be logged as this ID in database",
|
||||
"de": "Wenn Alias-ID gesetzt ist, werden die Daten als diese ID in der Datenbank protokolliert",
|
||||
"ru": "если установлен Alias-ID, данные будут регистрироваться как этот идентификатор в базе данных",
|
||||
"pt": "Se o Alias-ID for definido, os dados serão registrados como esse ID no banco de dados",
|
||||
"nl": "als Alias-ID is ingesteld, worden de gegevens als deze ID geregistreerd in de database",
|
||||
"fr": "Si Alias-ID est défini, les données seront enregistrées comme cet ID dans la base de données",
|
||||
"it": "se Alias-ID è impostato, i dati verranno registrati come questo ID nel database",
|
||||
"es": "si se establece Alias-ID, los datos se registrarán como esta ID en la base de datos",
|
||||
"pl": "jeśli ustawiony jest Alias-ID, dane będą rejestrowane jako identyfikator w bazie danych"
|
||||
}
|
||||
});
|
||||
// There are two ways how to predefine default settings:
|
||||
// - with attribute "data-default" (content independent)
|
||||
// - with function in global variable "defaults". Function name is equal with adapter name.
|
||||
// as input function receives object with all information concerning it
|
||||
if (typeof defaults !== 'undefined') {
|
||||
defaults.sql = function (obj, instanceObj) {
|
||||
if (obj && obj.common && obj.common.type !== 'number') {
|
||||
return {
|
||||
enabled: false,
|
||||
changesOnly: false,
|
||||
debounce: 0,
|
||||
maxLength: 10,
|
||||
retention: instanceObj.native.retention,
|
||||
changesRelogInterval: instanceObj.native.changesRelogInterval,
|
||||
changesMinDelta: 0,
|
||||
storageType: '',
|
||||
aliasId: ''
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
enabled: false,
|
||||
changesOnly: true,
|
||||
debounce: instanceObj.native.debounce,
|
||||
maxLength: instanceObj.native.maxLength,
|
||||
retention: instanceObj.native.retention,
|
||||
changesRelogInterval: instanceObj.native.changesRelogInterval,
|
||||
changesMinDelta: instanceObj.native.changesMinDelta,
|
||||
storageType: '',
|
||||
aliasId: ''
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
46
admin/i18n/de/translations.json
Normal file
46
admin/i18n/de/translations.json
Normal file
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"History adapter settings": "History-Adapter Einstellungen",
|
||||
"note": "History Einstellungen mussen für jeden State einzeln gemacht werden auf der Lasche \"States\" und nur wenn adapter aktiv ist",
|
||||
"Default settings:": "Default Einstellungen für Zuständen",
|
||||
"Start or enable adapter first": "Adapter muss zuerst aktiviert werden",
|
||||
"debounce": "Entprellzeit(ms)",
|
||||
"log changes interval(s)": "Gleiche Werte aufzeichnen(s)",
|
||||
"log changes minimal delta": "Minimale Abweichung vom letzten Wert für Aufzeichnung",
|
||||
"0 = disable delta check": "0 = Abweichungsprüfung deaktivieren",
|
||||
"0 = disable": "0 = Deaktivieren",
|
||||
"DB settings": "DB Einstellungen",
|
||||
"Default settings": "Default Einstellungen",
|
||||
"retention": "Storage Vorhaltezeit",
|
||||
"keep forever": "keine automatische Löschung",
|
||||
"2 years": "2 Jahre",
|
||||
"1 year": "1 Jahr",
|
||||
"6 months": "6 Monate",
|
||||
"3 months": "3 Monate",
|
||||
"1 months": "1 Monat",
|
||||
"2 weeks": "2 Wochen",
|
||||
"1 week": "1 Woche",
|
||||
"5 days": "5 Tage",
|
||||
"3 days": "3 Tage",
|
||||
"1 day": "1 Tag",
|
||||
"SQL history adapter settings": "SQL history adapter Einstellungen",
|
||||
"DB settings:": "DB Einstellungen",
|
||||
"DB Type": "DB Typ",
|
||||
"Host": "Host",
|
||||
"DB Name": "Datenbankname",
|
||||
"Port": "Port",
|
||||
"User": "Login",
|
||||
"Password": "Kennwort",
|
||||
"Password confirm": "Kennwort-Wiederholung",
|
||||
"File for sqlite:": "Datei für sqlite",
|
||||
"Encrypt:": "Verschlüsseln",
|
||||
"Test connection": "Verbindung testen",
|
||||
"requestInterval": "Intervall zwischen DB Anfragen(ms)",
|
||||
"Round real to:": "Aufrunden auf: ",
|
||||
"Password confirmation is not equal with password!": "Kennwort-Bestätigung ist nicht gleich mit dem Kennwort!",
|
||||
"Input path with the file name.": "Z.B. /opt/sqlite/data.db",
|
||||
"Are you sure? All data will be dropped.": "Sind Sie sicher? ALLE Daten werden geöscht.",
|
||||
"Reset DB": "Alle Daten in DB löschen",
|
||||
"Ok": "Ok",
|
||||
"Allow parallel requests:": "Parallelanfragen erlauben",
|
||||
"Write NULL values on start/stop boundaries:": "Schreibe NULL-Werte an Start- / Stop-Grenzen:"
|
||||
}
|
||||
46
admin/i18n/en/translations.json
Normal file
46
admin/i18n/en/translations.json
Normal file
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"History adapter settings": "History adapter settings",
|
||||
"note": "History settings must be done for every state individually on the tab \"States\" and only if adapter is active",
|
||||
"Default settings:": "Default settings",
|
||||
"Start or enable adapter first": "Start or enable adapter first",
|
||||
"debounce": "De-bounce interval(ms)",
|
||||
"log changes interval(s)": "Log unchanged values any(s)",
|
||||
"log changes minimal delta": "Minimum difference from last value to log",
|
||||
"0 = disable delta check": "0 = disable delta check",
|
||||
"0 = disable": "0 = disable",
|
||||
"DB settings": "DB settings",
|
||||
"Default settings": "Default settings",
|
||||
"retention": "Storage retention",
|
||||
"keep forever": "keep forever",
|
||||
"2 years": "2 years",
|
||||
"1 year": "1 year",
|
||||
"6 months": "6 months",
|
||||
"3 months": "3 months",
|
||||
"1 months": "1 months",
|
||||
"2 weeks": "2 weeks",
|
||||
"1 week": "1 week",
|
||||
"5 days": "5 days",
|
||||
"3 days": "3 days",
|
||||
"1 day": "1 day",
|
||||
"SQL history adapter settings": "SQL history adapter settings",
|
||||
"DB settings:": "DB settings",
|
||||
"DB Type": "DB Type",
|
||||
"Host": "Host",
|
||||
"DB Name": "Database name",
|
||||
"Port": "Port",
|
||||
"User": "User",
|
||||
"Password": "Password",
|
||||
"Password confirm": "Password confirm",
|
||||
"File for sqlite:": "File for sqlite",
|
||||
"Encrypt:": "Encrypt",
|
||||
"Test connection": "Test connection",
|
||||
"requestInterval": "Pause between requests(ms)",
|
||||
"Round real to:": "Round real to",
|
||||
"Password confirmation is not equal with password!": "Password confirmation is not equal with password!",
|
||||
"Input path with the file name.": "E.g. /opt/sqlite/data.db",
|
||||
"Are you sure? All data will be dropped.": "Are you sure? All data will be dropped.",
|
||||
"Reset DB": "Reset DB",
|
||||
"Ok": "Ok",
|
||||
"Allow parallel requests:": "Allow parallel requests",
|
||||
"Write NULL values on start/stop boundaries:": "Write NULL values on start/stop boundaries:"
|
||||
}
|
||||
46
admin/i18n/es/translations.json
Normal file
46
admin/i18n/es/translations.json
Normal file
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"History adapter settings": "Configuración del adaptador de historial",
|
||||
"note": "La configuración del historial se debe realizar para cada estado individualmente en la pestaña \"Estados\" y solo si el adaptador está activo",
|
||||
"Default settings:": "Configuración por defecto",
|
||||
"Start or enable adapter first": "Comience o habilite el adaptador primero",
|
||||
"debounce": "Intervalo de rebote (ms)",
|
||||
"log changes interval(s)": "Registre los valores sin modificar cualquier (s)",
|
||||
"log changes minimal delta": "Diferencia mínima desde el último valor para registrar",
|
||||
"0 = disable delta check": "0 = deshabilitar la verificación delta",
|
||||
"0 = disable": "0 = desactivar",
|
||||
"DB settings": "Configuración de DB",
|
||||
"Default settings": "Configuración por defecto",
|
||||
"retention": "Retención de almacenamiento",
|
||||
"keep forever": "mantener para siempre",
|
||||
"2 years": "2 años",
|
||||
"1 year": "1 año",
|
||||
"6 months": "6 meses",
|
||||
"3 months": "3 meses",
|
||||
"1 months": "1 mes",
|
||||
"2 weeks": "2 semanas",
|
||||
"1 week": "1 semana",
|
||||
"5 days": "5 dias",
|
||||
"3 days": "3 días",
|
||||
"1 day": "1 día",
|
||||
"SQL history adapter settings": "Configuración del adaptador de historial SQL",
|
||||
"DB settings:": "Configuración de DB",
|
||||
"DB Type": "Tipo de DB",
|
||||
"Host": "Anfitrión",
|
||||
"DB Name": "Nombre de la base de datos",
|
||||
"Port": "Puerto",
|
||||
"User": "Usuario",
|
||||
"Password": "Contraseña",
|
||||
"Password confirm": "Contraseña confirmada",
|
||||
"File for sqlite:": "Archivo para sqlite",
|
||||
"Encrypt:": "Encriptar",
|
||||
"Test connection": "Conexión de prueba",
|
||||
"requestInterval": "Pausa entre solicitudes (ms)",
|
||||
"Round real to:": "Redondo real para",
|
||||
"Password confirmation is not equal with password!": "La confirmación de la contraseña no es igual a la contraseña!",
|
||||
"Input path with the file name.": "P.ej. /opt/sqlite/data.db",
|
||||
"Are you sure? All data will be dropped.": "¿Estás seguro? Todos los datos serán eliminados.",
|
||||
"Reset DB": "Restablecer DB",
|
||||
"Ok": "De acuerdo",
|
||||
"Allow parallel requests:": "Permitir solicitudes paralelas",
|
||||
"Write NULL values on start/stop boundaries:": "Escribe valores NULL en los límites de inicio / finalización:"
|
||||
}
|
||||
46
admin/i18n/fr/translations.json
Normal file
46
admin/i18n/fr/translations.json
Normal file
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"History adapter settings": "Paramètres de l'adaptateur d'historique",
|
||||
"note": "Les paramètres d'historique doivent être définis pour chaque état individuellement dans l'onglet \"Etats\" et uniquement si l'adaptateur est actif",
|
||||
"Default settings:": "Paramètres par défaut",
|
||||
"Start or enable adapter first": "Démarrer ou activer l'adaptateur en premier",
|
||||
"debounce": "Intervalle de rebond (ms)",
|
||||
"log changes interval(s)": "Consigner les valeurs inchangées any (s)",
|
||||
"log changes minimal delta": "Différence minimale de la dernière valeur à la notation",
|
||||
"0 = disable delta check": "0 = désactiver le contrôle delta",
|
||||
"0 = disable": "0 = désactiver",
|
||||
"DB settings": "Paramètres DB",
|
||||
"Default settings": "Paramètres par défaut",
|
||||
"retention": "Rétention de stockage",
|
||||
"keep forever": "garde pour toujours",
|
||||
"2 years": "2 ans",
|
||||
"1 year": "1 an",
|
||||
"6 months": "6 mois",
|
||||
"3 months": "3 mois",
|
||||
"1 months": "1 mois",
|
||||
"2 weeks": "2 semaines",
|
||||
"1 week": "1 semaine",
|
||||
"5 days": "5 jours",
|
||||
"3 days": "3 jours",
|
||||
"1 day": "Un jour",
|
||||
"SQL history adapter settings": "Paramètres de l'adaptateur d'historique SQL",
|
||||
"DB settings:": "Paramètres de base de données",
|
||||
"DB Type": "Type de DB",
|
||||
"Host": "Hôte",
|
||||
"DB Name": "Nom de la base de données",
|
||||
"Port": "Port",
|
||||
"User": "Utilisateur",
|
||||
"Password": "Mot de passe",
|
||||
"Password confirm": "Confirmer le mot de passe",
|
||||
"File for sqlite:": "Fichier pour sqlite",
|
||||
"Encrypt:": "Crypter",
|
||||
"Test connection": "Test de connexion",
|
||||
"requestInterval": "Pause entre les demandes (ms)",
|
||||
"Round real to:": "Rond réel à",
|
||||
"Password confirmation is not equal with password!": "La confirmation du mot de passe n'est pas égale au mot de passe!",
|
||||
"Input path with the file name.": "Par exemple. /opt/sqlite/data.db",
|
||||
"Are you sure? All data will be dropped.": "Êtes-vous sûr? Toutes les données seront supprimées.",
|
||||
"Reset DB": "Reset DB",
|
||||
"Ok": "D'accord",
|
||||
"Allow parallel requests:": "Autoriser les demandes parallèles",
|
||||
"Write NULL values on start/stop boundaries:": "Écrire des valeurs NULL sur les limites de démarrage / arrêt:"
|
||||
}
|
||||
46
admin/i18n/it/translations.json
Normal file
46
admin/i18n/it/translations.json
Normal file
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"History adapter settings": "Impostazioni della scheda Cronologia",
|
||||
"note": "Le impostazioni della cronologia devono essere eseguite singolarmente per ogni stato nella scheda \"Stati\" e solo se l'adattatore è attivo",
|
||||
"Default settings:": "Impostazioni predefinite",
|
||||
"Start or enable adapter first": "Inizia o abilita prima l'adattatore",
|
||||
"debounce": "Intervallo di rimbalzo (ms)",
|
||||
"log changes interval(s)": "Registra valori invariati nessuno (i)",
|
||||
"log changes minimal delta": "Differenza minima dall'ultimo valore da registrare",
|
||||
"0 = disable delta check": "0 = disabilita il controllo delta",
|
||||
"0 = disable": "0 = disabilita",
|
||||
"DB settings": "Impostazioni DB",
|
||||
"Default settings": "Impostazioni predefinite",
|
||||
"retention": "Conservazione dello spazio",
|
||||
"keep forever": "tienilo per sempre",
|
||||
"2 years": "2 anni",
|
||||
"1 year": "1 anno",
|
||||
"6 months": "6 mesi",
|
||||
"3 months": "3 mesi",
|
||||
"1 months": "1 mese",
|
||||
"2 weeks": "2 settimane",
|
||||
"1 week": "1 settimana",
|
||||
"5 days": "5 giorni",
|
||||
"3 days": "3 giorni",
|
||||
"1 day": "1 giorno",
|
||||
"SQL history adapter settings": "Impostazioni della scheda cronologia SQL",
|
||||
"DB settings:": "Impostazioni DB",
|
||||
"DB Type": "Tipo di DB",
|
||||
"Host": "Ospite",
|
||||
"DB Name": "Nome del database",
|
||||
"Port": "Porta",
|
||||
"User": "Utente",
|
||||
"Password": "Parola d'ordine",
|
||||
"Password confirm": "Conferma la password",
|
||||
"File for sqlite:": "File per sqlite",
|
||||
"Encrypt:": "Encrypt",
|
||||
"Test connection": "Connessione di prova",
|
||||
"requestInterval": "Pausa tra le richieste (ms)",
|
||||
"Round real to:": "Round reale a",
|
||||
"Password confirmation is not equal with password!": "La conferma della password non è uguale alla password!",
|
||||
"Input path with the file name.": "Per esempio. /opt/sqlite/data.db",
|
||||
"Are you sure? All data will be dropped.": "Sei sicuro? Tutti i dati verranno eliminati.",
|
||||
"Reset DB": "Ripristina DB",
|
||||
"Ok": "Ok",
|
||||
"Allow parallel requests:": "Consenti richieste parallele",
|
||||
"Write NULL values on start/stop boundaries:": "Scrivi valori NULL sui limiti di avvio / arresto:"
|
||||
}
|
||||
46
admin/i18n/nl/translations.json
Normal file
46
admin/i18n/nl/translations.json
Normal file
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"History adapter settings": "Geschiedenis adapter instellingen",
|
||||
"note": "Geschiedenisinstellingen moeten voor elke afzonderlijke status worden uitgevoerd op het tabblad \"Staten\" en alleen als de adapter actief is",
|
||||
"Default settings:": "Standaard instellingen",
|
||||
"Start or enable adapter first": "Start of schakel eerst de adapter in",
|
||||
"debounce": "De-bounce interval (ms)",
|
||||
"log changes interval(s)": "Log onveranderde waarden voor elke",
|
||||
"log changes minimal delta": "Minimaal verschil van laatste waarde tot log",
|
||||
"0 = disable delta check": "0 = delta-controle uitschakelen",
|
||||
"0 = disable": "0 = uitschakelen",
|
||||
"DB settings": "DB-instellingen",
|
||||
"Default settings": "Standaard instellingen",
|
||||
"retention": "Bewaring van opslag",
|
||||
"keep forever": "blijf voor altijd",
|
||||
"2 years": "2 jaar",
|
||||
"1 year": "1 jaar",
|
||||
"6 months": "6 maanden",
|
||||
"3 months": "3 maanden",
|
||||
"1 months": "1 maanden",
|
||||
"2 weeks": "2 weken",
|
||||
"1 week": "1 week",
|
||||
"5 days": "5 dagen",
|
||||
"3 days": "3 dagen",
|
||||
"1 day": "1 dag",
|
||||
"SQL history adapter settings": "Instellingen voor SQL-geschiedenisadapter",
|
||||
"DB settings:": "DB-instellingen",
|
||||
"DB Type": "DB Type",
|
||||
"Host": "Host",
|
||||
"DB Name": "Database naam",
|
||||
"Port": "Haven",
|
||||
"User": "Gebruiker",
|
||||
"Password": "Wachtwoord",
|
||||
"Password confirm": "Wachtwoord bevestigen",
|
||||
"File for sqlite:": "Bestand voor sqlite",
|
||||
"Encrypt:": "versleutelen",
|
||||
"Test connection": "Test verbinding",
|
||||
"requestInterval": "Pauzeren tussen verzoeken (ms)",
|
||||
"Round real to:": "Rond echt naar",
|
||||
"Password confirmation is not equal with password!": "Wachtwoordbevestiging is niet gelijk aan wachtwoord!",
|
||||
"Input path with the file name.": "Bijv. /opt/sqlite/data.db",
|
||||
"Are you sure? All data will be dropped.": "Weet je het zeker? Alle gegevens worden verwijderd.",
|
||||
"Reset DB": "Stel DB opnieuw in",
|
||||
"Ok": "OK",
|
||||
"Allow parallel requests:": "Sta parallelle verzoeken toe",
|
||||
"Write NULL values on start/stop boundaries:": "Schrijf NULL-waarden op start / stop-grenzen:"
|
||||
}
|
||||
46
admin/i18n/pl/translations.json
Normal file
46
admin/i18n/pl/translations.json
Normal file
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"History adapter settings": "Ustawienia adaptera historii",
|
||||
"note": "Ustawienia historii muszą być wykonane dla każdego stanu indywidualnie na karcie \"Stany\" i tylko wtedy, gdy adapter jest aktywny",
|
||||
"Default settings:": "Ustawienia domyślne",
|
||||
"Start or enable adapter first": "Najpierw włącz lub włącz adapter",
|
||||
"debounce": "Interwał odbicia (ms)",
|
||||
"log changes interval(s)": "Zaloguj niezmienione wartości dowolne (s)",
|
||||
"log changes minimal delta": "Minimalna różnica od ostatniej wartości do dziennika",
|
||||
"0 = disable delta check": "0 = wyłącz kontrolę delta",
|
||||
"0 = disable": "0 = wyłącz",
|
||||
"DB settings": "Ustawienia DB",
|
||||
"Default settings": "Ustawienia domyślne",
|
||||
"retention": "Zatrzymanie przechowywania",
|
||||
"keep forever": "zachowaj na zawsze",
|
||||
"2 years": "2 lata",
|
||||
"1 year": "1 rok",
|
||||
"6 months": "6 miesięcy",
|
||||
"3 months": "3 miesiące",
|
||||
"1 months": "1 miesiąc",
|
||||
"2 weeks": "2 tygodnie",
|
||||
"1 week": "1 tydzień",
|
||||
"5 days": "5 dni",
|
||||
"3 days": "3 dni",
|
||||
"1 day": "1 dzień",
|
||||
"SQL history adapter settings": "Ustawienia adaptera historii SQL",
|
||||
"DB settings:": "Ustawienia DB",
|
||||
"DB Type": "Typ DB",
|
||||
"Host": "Gospodarz",
|
||||
"DB Name": "Nazwa bazy danych",
|
||||
"Port": "Port",
|
||||
"User": "Użytkownik",
|
||||
"Password": "Hasło",
|
||||
"Password confirm": "Potwierdź hasło",
|
||||
"File for sqlite:": "Plik dla sqlite",
|
||||
"Encrypt:": "Szyfruj",
|
||||
"Test connection": "Testuj połączenie",
|
||||
"requestInterval": "Wstrzymaj między żądaniami (ms)",
|
||||
"Round real to:": "Runda prawdziwa do",
|
||||
"Password confirmation is not equal with password!": "Potwierdzenie hasła nie jest równe hasłu!",
|
||||
"Input path with the file name.": "Na przykład. /opt/sqlite/data.db",
|
||||
"Are you sure? All data will be dropped.": "Jesteś pewny? Wszystkie dane zostaną usunięte.",
|
||||
"Reset DB": "Zresetuj DB",
|
||||
"Ok": "Ok",
|
||||
"Allow parallel requests:": "Pozwól na równoległe żądania",
|
||||
"Write NULL values on start/stop boundaries:": "Napisz wartości NULL na granicach start / stop:"
|
||||
}
|
||||
46
admin/i18n/pt/translations.json
Normal file
46
admin/i18n/pt/translations.json
Normal file
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"History adapter settings": "Configurações do adaptador de histórico",
|
||||
"note": "As configurações de histórico devem ser feitas para cada estado individual na guia \"Estados\" e somente se o adaptador estiver ativo",
|
||||
"Default settings:": "Configurações padrão",
|
||||
"Start or enable adapter first": "Inicie ou ative o adaptador primeiro",
|
||||
"debounce": "Intervalo de desvio (ms)",
|
||||
"log changes interval(s)": "Registre valores inalterados qualquer (s)",
|
||||
"log changes minimal delta": "Diferença mínima do último valor ao log",
|
||||
"0 = disable delta check": "0 = desativar o cheque delta",
|
||||
"0 = disable": "0 = desativar",
|
||||
"DB settings": "Configurações de banco de dados",
|
||||
"Default settings": "Configurações padrão",
|
||||
"retention": "Retenção de armazenamento",
|
||||
"keep forever": "mantenha para sempre",
|
||||
"2 years": "2 anos",
|
||||
"1 year": "1 ano",
|
||||
"6 months": "6 meses",
|
||||
"3 months": "3 meses",
|
||||
"1 months": "1 mês",
|
||||
"2 weeks": "2 semanas",
|
||||
"1 week": "1 semana",
|
||||
"5 days": "5 dias",
|
||||
"3 days": "3 dias",
|
||||
"1 day": "1 dia",
|
||||
"SQL history adapter settings": "Configurações do adaptador de histórico SQL",
|
||||
"DB settings:": "Configurações de banco de dados",
|
||||
"DB Type": "DB Type",
|
||||
"Host": "Hospedeiro",
|
||||
"DB Name": "Nome do banco de dados",
|
||||
"Port": "Porta",
|
||||
"User": "Do utilizador",
|
||||
"Password": "Senha",
|
||||
"Password confirm": "Confirmação de senha",
|
||||
"File for sqlite:": "Arquivo para sqlite",
|
||||
"Encrypt:": "Criptografar",
|
||||
"Test connection": "Conexão de teste",
|
||||
"requestInterval": "Pausa entre solicitações (ms)",
|
||||
"Round real to:": "Round real to",
|
||||
"Password confirmation is not equal with password!": "A confirmação da senha não é igual com a senha!",
|
||||
"Input path with the file name.": "Por exemplo. /opt/sqlite/data.db",
|
||||
"Are you sure? All data will be dropped.": "Você tem certeza? Todos os dados serão descartados.",
|
||||
"Reset DB": "Redefinir DB",
|
||||
"Ok": "Está bem",
|
||||
"Allow parallel requests:": "Permitir pedidos paralelos",
|
||||
"Write NULL values on start/stop boundaries:": "Escreva valores NULL nos limites de início / parada:"
|
||||
}
|
||||
46
admin/i18n/ru/translations.json
Normal file
46
admin/i18n/ru/translations.json
Normal file
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"History adapter settings": "Настройки профайлера",
|
||||
"note": "Настройки профайлера делаются для каждого состояния отдельно в закладке \"Состояния\" и только, когда драйвер активирован",
|
||||
"Default settings:": "Настройки по умолчанию для состояний",
|
||||
"Start or enable adapter first": "Сначала надо активировать драйвер SQL",
|
||||
"debounce": "Минимальный интервал(ms)",
|
||||
"log changes interval(s)": "Запись неизменённых значений каждые (сек)",
|
||||
"log changes minimal delta": "Минимальная разница с последним записанным значением",
|
||||
"0 = disable delta check": "0 = не проверять минимальное изменение",
|
||||
"0 = disable": "0 = не активно",
|
||||
"DB settings": "Настройки соединения с DB",
|
||||
"Default settings": "Настройки по умолчанию",
|
||||
"retention": "Время хранения в базе",
|
||||
"keep forever": "хранить вечно",
|
||||
"2 years": "2 года",
|
||||
"1 year": "1 год",
|
||||
"6 months": "6 месяцев",
|
||||
"3 months": "3 месяца",
|
||||
"1 months": "1 месяц",
|
||||
"2 weeks": "2 недели",
|
||||
"1 week": "1 неделя",
|
||||
"5 days": "5 дней",
|
||||
"3 days": "3 дня",
|
||||
"1 day": "1 день",
|
||||
"SQL history adapter settings": "Настройки профайлера в SQL базу данных",
|
||||
"DB settings:": "DB settings",
|
||||
"DB Type": "DB Type",
|
||||
"Host": "Хост",
|
||||
"DB Name": "Имя базы данных",
|
||||
"Port": "Порт",
|
||||
"User": "Пользователь",
|
||||
"Password": "Пароль",
|
||||
"Password confirm": "Подтверждение пароля",
|
||||
"File for sqlite:": "Файл для sqlite",
|
||||
"Encrypt:": "Шифрование",
|
||||
"Test connection": "Проверить соединение",
|
||||
"requestInterval": "Пауза между запросами к базе",
|
||||
"Round real to:": "Округлять до",
|
||||
"Password confirmation is not equal with password!": "Подтверждение пароля не совпадает с паролем!",
|
||||
"Input path with the file name.": "Например /opt/sqlite/data.db",
|
||||
"Are you sure? All data will be dropped.": "Вы уверенны? Все данные в базе будут удалены.",
|
||||
"Reset DB": "Сбросить DB",
|
||||
"Ok": "Ok",
|
||||
"Allow parallel requests:": "Разрешить параллельные запросы к базе",
|
||||
"Write NULL values on start/stop boundaries:": "Запись значений NULL на границах начала / остановки:"
|
||||
}
|
||||
276
admin/index.html
Normal file
276
admin/index.html
Normal file
@@ -0,0 +1,276 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
<!-- these 4 files always have to be included -->
|
||||
<link rel="stylesheet" type="text/css" href="../../lib/css/themes/jquery-ui/redmond/jquery-ui.min.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>
|
||||
|
||||
<!-- these three files have to be always included -->
|
||||
<link rel="stylesheet" type="text/css" href="../../css/adapter.css"/>
|
||||
<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>
|
||||
|
||||
<!-- you have to define 2 functions in the global scope: -->
|
||||
<script type="text/javascript">
|
||||
var convertComma = null;
|
||||
function setValue(id, value, onChange) {
|
||||
var $value = $('#' + id + '.value');
|
||||
if ($value.attr('type') === 'checkbox') {
|
||||
$value.prop('checked', value).change(function () {
|
||||
onChange();
|
||||
});
|
||||
} else {
|
||||
$value.val(value).change(function() {
|
||||
onChange();
|
||||
}).keyup(function() {
|
||||
// Check that only numbers entered
|
||||
if ($(this).hasClass('number')) {
|
||||
var val = $(this).val();
|
||||
if (val) {
|
||||
var newVal = '';
|
||||
for (var i = 0; i < val.length; i++) {
|
||||
if ((val[i] >= '0' && val[i] <= '9') || val[i] === '-' || val[i] === '+' || val[i] === '.' || val[i] === ',') {
|
||||
if (val[i] === '.' && convertComma === true) val[i] = ',';
|
||||
if (val[i] === ',' && convertComma === false) val[i] = '.';
|
||||
newVal += val[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (val != newVal) {
|
||||
$(this).val(newVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
$(this).trigger('change');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function load(settings, onChange) {
|
||||
$('#tabs').tabs();
|
||||
|
||||
// works only with newest admin adapter
|
||||
if (typeof systemConfig !== 'undefined') {
|
||||
convertComma = systemConfig.common.isFloatComma;
|
||||
}
|
||||
|
||||
if (settings.writeNulls === undefined) settings.writeNulls = true;
|
||||
for (var key in settings) {
|
||||
if (settings.hasOwnProperty(key)) {
|
||||
setValue(key, settings[key], onChange);
|
||||
}
|
||||
}
|
||||
$('#passwordConfirm').val(settings.password);
|
||||
|
||||
$('#test').button().click(function () {
|
||||
getIsAdapterAlive(function (isAlive) {
|
||||
if (!isAlive) {
|
||||
showMessage(_('Start or enable adapter first'));
|
||||
} else {
|
||||
$('#test').button('option', 'disabled', true);
|
||||
sendTo(null, 'test', {
|
||||
config: {
|
||||
dbtype: $('#dbtype').val(),
|
||||
port: $('#port').val(),
|
||||
host: $('#host').val(),
|
||||
user: $('#user').val(),
|
||||
fileName: $('#fileName').val(),
|
||||
password: $('#password').val()
|
||||
}
|
||||
}, function (response) {
|
||||
$('#test').button('option', 'disabled', false);
|
||||
showMessage(response.error || 'OK');
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('#reset').button().click(function () {
|
||||
getIsAdapterAlive(function (isAlive) {
|
||||
if (!isAlive) {
|
||||
showMessage(_('Start or enable adapter first'));
|
||||
} else {
|
||||
if (confirm(_('Are you sure? All data will be dropped.'))) {
|
||||
$('#reset').button('option', 'disabled', true);
|
||||
sendTo(null, 'destroy', null, function (response) {
|
||||
$('#reset').button('option', 'disabled', false);
|
||||
showMessage(response.error || _('Adapter will be restarted'));
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#dbtype').change(function () {
|
||||
if ($(this).val() === 'sqlite') {
|
||||
$('.baby-sql').show();
|
||||
$('.real-sql').hide();
|
||||
$('.ms-sql').hide();
|
||||
} else if ($(this).val() === 'mssql') {
|
||||
$('.baby-sql').hide();
|
||||
$('.real-sql').show();
|
||||
$('.ms-sql').show();
|
||||
} else {
|
||||
$('.baby-sql').hide();
|
||||
$('.ms-sql').hide();
|
||||
$('.real-sql').show();
|
||||
}
|
||||
}).trigger('change');
|
||||
|
||||
onChange(false);
|
||||
}
|
||||
|
||||
function save(callback) {
|
||||
var settings = {};
|
||||
$('.value').each(function () {
|
||||
var $this = $(this);
|
||||
var id = $this.attr('id');
|
||||
|
||||
if ($this.attr('type') === 'checkbox') {
|
||||
settings[id] = $this.prop('checked');
|
||||
} else {
|
||||
settings[id] = $this.val();
|
||||
}
|
||||
});
|
||||
|
||||
if (($('#dbtype').val() !== 'sqlite') && ($('#passwordConfirm').val() !== $('#password').val())) {
|
||||
showMessage(_('Password confirmation is not equal with password!'));
|
||||
return;
|
||||
}
|
||||
|
||||
callback(settings);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="adapter-container">
|
||||
<table><tr>
|
||||
<td><img src="sql.png"></td>
|
||||
<td style="padding-top: 20px;padding-left: 10px"><h3 class="translate">SQL history adapter settings</h3></td>
|
||||
</tr></table>
|
||||
<div id="tabs">
|
||||
<ul>
|
||||
<li><a href="#tabs-1" class="translate">DB settings</a></li>
|
||||
<li><a href="#tabs-2" class="translate">Default settings</a></li>
|
||||
</ul>
|
||||
<div id="tabs-1">
|
||||
<table>
|
||||
<tr>
|
||||
<td><label class="translate" for="dbtype">DB Type</label></td>
|
||||
<td><select id="dbtype" class="value">
|
||||
<option value="mysql">MySQL</option>
|
||||
<option value="postgresql">PostgreSQL</option>
|
||||
<option value="sqlite">SQLite3</option>
|
||||
<option value="mssql">MS-SQL</option>
|
||||
</select></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr class="real-sql">
|
||||
<td><label class="translate" for="host">Host</label></td>
|
||||
<td><input id="host" class="value"/></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr class="real-sql">
|
||||
<td><label class="translate" for="port">Port</label></td>
|
||||
<td><input id="port" class="value"/></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr class="ms-sql real-sql">
|
||||
<td><label class="translate" for="dbname">DB Name</label></td>
|
||||
<td><input id="dbname" class="value"/></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr class="real-sql">
|
||||
<td><label class="translate" for="user">User</label></td>
|
||||
<td><input id="user" class="value"/></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr class="real-sql">
|
||||
<td><label class="translate" for="password">Password</label></td>
|
||||
<td><input id="password" type="password" class="value"/></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr class="real-sql">
|
||||
<td><label class="translate" for="passwordConfirm">Password confirm</label></td>
|
||||
<td><input id="passwordConfirm" type="password"/></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr class="baby-sql">
|
||||
<td><label class="translate" for="fileName">File for sqlite:</label></td>
|
||||
<td><input id="fileName" class="value"/></td>
|
||||
<td class="translate">Input path with the file name.</td>
|
||||
</tr>
|
||||
<tr class="baby-sql">
|
||||
<td><label class="translate" for="requestInterval">requestInterval</label></td>
|
||||
<td><input id="requestInterval" class="value"/></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr class="ms-sql real-sql">
|
||||
<td><label class="translate" for="encrypt">Encrypt:</label></td>
|
||||
<td><input id="encrypt" type="checkbox" class="value"/></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr class="ms-sql real-sql">
|
||||
<td><label class="translate" for="round">Round real to:</label></td>
|
||||
<td><input id="round" class="value"/></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr class="ms-sql real-sql">
|
||||
<td><label class="translate" for="multiRequests">Allow parallel requests:</label></td>
|
||||
<td><input id="multiRequests" type="checkbox" class="value"/></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label class="translate" for="writeNulls">Write NULL values on start/stop boundaries:</label></td>
|
||||
<td><input id="writeNulls" type="checkbox" class="value"/></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<button id="test" class="translate">Test connection</button>
|
||||
<button id="reset" class="translate">Reset DB</button>
|
||||
</div>
|
||||
<div id="tabs-2">
|
||||
<table>
|
||||
<tr><td colspan="3"><h4 class="translate">Default settings:</h4></td></tr>
|
||||
<tr>
|
||||
<td><label class="translate" for="debounce">debounce</label></td>
|
||||
<td><input id="debounce" size="5" class="value number"/></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label class="translate" for="changesRelogInterval">log changes interval(s)</label></td>
|
||||
<td><input id="changesRelogInterval" size="5" class="value number"/></td>
|
||||
<td class="translate">0 = disable</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label class="translate" for="changesMinDelta">log changes minimal delta</label></td>
|
||||
<td><input id="changesMinDelta" size="5" class="value number"/></td>
|
||||
<td class="translate">0 = disable delta check</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label class="translate" for="retention">retention</label></td>
|
||||
<td><select id="retention" class="value">
|
||||
<option value="0" class="translate">keep forever</option>
|
||||
<option value="63072000" class="translate">2 years</option>
|
||||
<option value="31536000" class="translate">1 year</option>
|
||||
<option value="15811200" class="translate">6 months</option>
|
||||
<option value="7948800" class="translate">3 months</option>
|
||||
<option value="2678400" class="translate">1 months</option>
|
||||
<option value="1209600" class="translate">2 weeks</option>
|
||||
<option value="604800" class="translate">1 week</option>
|
||||
<option value="432000" class="translate">5 days</option>
|
||||
<option value="259200" class="translate">3 days</option>
|
||||
<option value="86400" class="translate">1 day</option>
|
||||
</select></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
296
admin/index_m.html
Normal file
296
admin/index_m.html
Normal file
@@ -0,0 +1,296 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<!-- Materialze style -->
|
||||
<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-3.2.1.min.js"></script>
|
||||
<script type="text/javascript" src="../../socket.io/socket.io.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="words.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
var convertComma = null;
|
||||
function setValue(id, value, onChange) {
|
||||
var $value = $('#' + id + '.value');
|
||||
if ($value.attr('type') === 'checkbox') {
|
||||
$value.prop('checked', value).change(function () {
|
||||
onChange();
|
||||
});
|
||||
} else {
|
||||
$value.val(value).change(function() {
|
||||
onChange();
|
||||
}).keyup(function() {
|
||||
// Check that only numbers entered
|
||||
if ($(this).hasClass('number')) {
|
||||
var val = $(this).val();
|
||||
if (val) {
|
||||
var newVal = '';
|
||||
for (var i = 0; i < val.length; i++) {
|
||||
if ((val[i] >= '0' && val[i] <= '9') || val[i] === '-' || val[i] === '+' || val[i] === '.' || val[i] === ',') {
|
||||
if (val[i] === '.' && convertComma === true) val[i] = ',';
|
||||
if (val[i] === ',' && convertComma === false) val[i] = '.';
|
||||
newVal += val[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (val != newVal) {
|
||||
$(this).val(newVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
$(this).trigger('change');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function load(settings, onChange) {
|
||||
// works only with newest admin adapter
|
||||
if (typeof systemConfig !== 'undefined') {
|
||||
convertComma = systemConfig.common.isFloatComma;
|
||||
}
|
||||
|
||||
if (settings.writeNulls === undefined) settings.writeNulls = true;
|
||||
for (var key in settings) {
|
||||
if (settings.hasOwnProperty(key)) {
|
||||
setValue(key, settings[key], onChange);
|
||||
}
|
||||
}
|
||||
$('#passwordConfirm').val(settings.password);
|
||||
|
||||
$('#test').on('click', function () {
|
||||
getIsAdapterAlive(function (isAlive) {
|
||||
if (!isAlive) {
|
||||
showToast(null, _('Start or enable adapter first'));
|
||||
} else {
|
||||
$('#test').addClass('disabled');
|
||||
sendTo(null, 'test', {
|
||||
config: {
|
||||
dbtype: $('#dbtype').val(),
|
||||
port: $('#port').val(),
|
||||
host: $('#host').val(),
|
||||
user: $('#user').val(),
|
||||
fileName: $('#fileName').val(),
|
||||
password: $('#password').val()
|
||||
}
|
||||
}, function (response) {
|
||||
$('#test').removeClass('disabled');
|
||||
if (response.error) {
|
||||
showError(response.error);
|
||||
} else {
|
||||
showMessage('OK');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('#reset').on('click', function () {
|
||||
getIsAdapterAlive(function (isAlive) {
|
||||
if (!isAlive) {
|
||||
showToast(null, _('Start or enable adapter first'));
|
||||
} else {
|
||||
if (confirm(_('Are you sure? All data will be dropped.'))) {
|
||||
$('#reset').addClass('disabled');
|
||||
sendTo(null, 'destroy', null, function (response) {
|
||||
$('#reset').removeClass('disabled');
|
||||
if (response.error) {
|
||||
showError(response.error);
|
||||
} else {
|
||||
showToast(null, _('Adapter will be restarted'));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#dbtype').on('change', function () {
|
||||
if ($(this).val() === 'sqlite') {
|
||||
$('.baby-sql').show();
|
||||
$('.real-sql').hide();
|
||||
$('.ms-sql').hide();
|
||||
} else if ($(this).val() === 'mssql') {
|
||||
$('.baby-sql').hide();
|
||||
$('.real-sql').show();
|
||||
$('.ms-sql').show();
|
||||
} else {
|
||||
$('.baby-sql').hide();
|
||||
$('.ms-sql').hide();
|
||||
$('.real-sql').show();
|
||||
}
|
||||
}).trigger('change');
|
||||
|
||||
onChange(false);
|
||||
if (M) M.updateTextFields();
|
||||
}
|
||||
|
||||
function save(callback) {
|
||||
var settings = {};
|
||||
$('.value').each(function () {
|
||||
var $this = $(this);
|
||||
var id = $this.attr('id');
|
||||
|
||||
if ($this.attr('type') === 'checkbox') {
|
||||
settings[id] = $this.prop('checked');
|
||||
} else {
|
||||
settings[id] = $this.val();
|
||||
}
|
||||
});
|
||||
|
||||
if (($('#dbtype').val() !== 'sqlite') && ($('#passwordConfirm').val() !== $('#password').val())) {
|
||||
showMessage(_('Password confirmation is not equal with password!'));
|
||||
return;
|
||||
}
|
||||
|
||||
callback(settings);
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.adapter-container>div {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
.page {
|
||||
height: calc(100% - 50px) !important;
|
||||
}
|
||||
.marg{
|
||||
margin-top: 3em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="m adapter-container">
|
||||
<div class="row">
|
||||
<div class="col s12">
|
||||
<ul class="tabs">
|
||||
<li class="tab col s3"><a href="#tab-main" class="translate active">DB settings</a></li>
|
||||
<li class="tab col s3"><a href="#tab-default" class="translate">Default settings</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="tab-main" class="col s12 page">
|
||||
<div class="row">
|
||||
<div class="col s6">
|
||||
<img src="sql.png" class="logo">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="input-field col s12 m4">
|
||||
<select id="dbtype" class="value">
|
||||
<option value="mysql">MySQL</option>
|
||||
<option value="postgresql">PostgreSQL</option>
|
||||
<option value="sqlite">SQLite3</option>
|
||||
<option value="mssql">MS-SQL</option>
|
||||
</select>
|
||||
<label class="translate" for="dbtype">DB Type</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="input-field real-sql col s12 m3 l4">
|
||||
<input id="host" type="text" class="value" />
|
||||
<label class="translate" for="host">Host</label>
|
||||
</div>
|
||||
<div class="input-field real-sql col s12 m3 l4 ">
|
||||
<input id="port" type="number" min="1" max="65565" class="value" />
|
||||
<label class="translate" for="port">Port</label>
|
||||
</div>
|
||||
<div class="input-field ms-sql real-sql col s12 m6 l4">
|
||||
<input id="dbname" type="text" class="value" />
|
||||
<label class="translate" for="dbname">DB Name</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row real-sql">
|
||||
<div class="input-field col s12 m6 l4">
|
||||
<input id="user" type="text" class="value" />
|
||||
<label class="translate" for="user">User</label>
|
||||
</div>
|
||||
<div class="input-field col s12 m3 l4">
|
||||
<input id="password" type="password" class="value" />
|
||||
<label class="translate" for="password">Password</label>
|
||||
</div>
|
||||
<div class="input-field col s12 m3 l4">
|
||||
<input id="passwordConfirm" type="password" />
|
||||
<label class="translate" for="passwordConfirm">Password confirm</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row baby-sql">
|
||||
<div class="input-field col s12 m6 l4">
|
||||
<input id="fileName" type="text" class="value" />
|
||||
<label for="fileName" class="translate">File for sqlite:</label>
|
||||
<span class="translate">Input path with the file name.</span>
|
||||
</div>
|
||||
<div class="input-field col s12 m6 l4">
|
||||
<input id="requestInterval" type="number" class="value" />
|
||||
<label class="translate" for="requestInterval">requestInterval</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row ms-sql real-sql">
|
||||
<div class="input-field col s12 m4">
|
||||
<input id="encrypt" type="checkbox" class="value" />
|
||||
<label class="translate" for="encrypt">Encrypt:</label>
|
||||
</div>
|
||||
<div class="input-field col s12 m4">
|
||||
<input id="round" type="text" class="value" />
|
||||
<label class="translate" for="round">Round real to:</label>
|
||||
</div>
|
||||
<div class="input-field col s12 m4">
|
||||
<input id="multiRequests" type="checkbox" class="value" />
|
||||
<label class="translate" for="multiRequests">Allow parallel requests:</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="input-field col s12 m4">
|
||||
<input id="writeNulls" type="checkbox" class="value" />
|
||||
<label class="translate" for="writeNulls">Write NULL values on start/stop boundaries:</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col s12">
|
||||
<a id="test" class="waves-effect waves-light btn"><i class="material-icons left">wifi_tethering</i><span class="translate">Test connection</span></a>
|
||||
<a id="reset" class="waves-effect waves-light btn"><i class="material-icons left">report</i><span class="translate">Reset DB</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="tab-default" class="col s12 page">
|
||||
<div class="row marg">
|
||||
<div class="input-field col s12 m6 l4">
|
||||
<input id="debounce" size="5" class="value" type="number" />
|
||||
<label class="translate" for="debounce">debounce</label>
|
||||
</div>
|
||||
<div class="input-field col s12 m6 l4">
|
||||
<input id="changesRelogInterval" size="5" class="value" type="number" />
|
||||
<label for="changesRelogInterval" class="translate">log changes interval(s)</label>
|
||||
(<span class="translate">0 = disable</span>)
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="input-field col s12 m6 l4">
|
||||
<input id="changesMinDelta" type="number" size="5" class="value" />
|
||||
<label for="changesMinDelta" class="translate">log changes minimal delta</label>
|
||||
(<span class="translate">0 = disable delta check</span>)
|
||||
</div>
|
||||
<div class="input-field col s12 m6 l4">
|
||||
<select id="retention" class="value">
|
||||
<option value="0" class="translate">keep forever</option>
|
||||
<option value="63072000" class="translate">2 years</option>
|
||||
<option value="31536000" class="translate">1 year</option>
|
||||
<option value="15811200" class="translate">6 months</option>
|
||||
<option value="7948800" class="translate">3 months</option>
|
||||
<option value="2678400" class="translate">1 months</option>
|
||||
<option value="1209600" class="translate">2 weeks</option>
|
||||
<option value="604800" class="translate">1 week</option>
|
||||
<option value="432000" class="translate">5 days</option>
|
||||
<option value="259200" class="translate">3 days</option>
|
||||
<option value="86400" class="translate">1 day</option>
|
||||
</select>
|
||||
<label class="translate" for="retention">retention</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
BIN
admin/sql.png
Normal file
BIN
admin/sql.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
60
admin/words.js
Normal file
60
admin/words.js
Normal file
@@ -0,0 +1,60 @@
|
||||
// DO NOT EDIT THIS FILE!!! IT WILL BE AUTOMATICALLY GENERATED FROM src/i18n
|
||||
/*global systemDictionary:true */
|
||||
'use strict';
|
||||
|
||||
systemDictionary = {
|
||||
"History adapter settings": { "en": "History adapter settings", "de": "History-Adapter Einstellungen", "ru": "Настройки профайлера", "pt": "Configurações do adaptador de histórico", "nl": "Geschiedenis adapter instellingen", "fr": "Paramètres de l'adaptateur d'historique", "it": "Impostazioni della scheda Cronologia", "es": "Configuración del adaptador de historial", "pl": "Ustawienia adaptera historii"},
|
||||
"note": { "en": "History settings must be done for every state individually on the tab \"States\" and only if adapter is active", "de": "History Einstellungen mussen für jeden State einzeln gemacht werden auf der Lasche \"States\" und nur wenn adapter aktiv ist", "ru": "Настройки профайлера делаются для каждого состояния отдельно в закладке \"Состояния\" и только, когда драйвер активирован", "pt": "As configurações de histórico devem ser feitas para cada estado individual na guia \"Estados\" e somente se o adaptador estiver ativo", "nl": "Geschiedenisinstellingen moeten voor elke afzonderlijke status worden uitgevoerd op het tabblad \"Staten\" en alleen als de adapter actief is", "fr": "Les paramètres d'historique doivent être définis pour chaque état individuellement dans l'onglet \"Etats\" et uniquement si l'adaptateur est actif", "it": "Le impostazioni della cronologia devono essere eseguite singolarmente per ogni stato nella scheda \"Stati\" e solo se l'adattatore è attivo", "es": "La configuración del historial se debe realizar para cada estado individualmente en la pestaña \"Estados\" y solo si el adaptador está activo", "pl": "Ustawienia historii muszą być wykonane dla każdego stanu indywidualnie na karcie \"Stany\" i tylko wtedy, gdy adapter jest aktywny"},
|
||||
"Default settings:": { "en": "Default settings", "de": "Default Einstellungen für Zuständen", "ru": "Настройки по умолчанию для состояний", "pt": "Configurações padrão", "nl": "Standaard instellingen", "fr": "Paramètres par défaut", "it": "Impostazioni predefinite", "es": "Configuración por defecto", "pl": "Ustawienia domyślne"},
|
||||
"Start or enable adapter first": { "en": "Start or enable adapter first", "de": "Adapter muss zuerst aktiviert werden", "ru": "Сначала надо активировать драйвер SQL", "pt": "Inicie ou ative o adaptador primeiro", "nl": "Start of schakel eerst de adapter in", "fr": "Démarrer ou activer l'adaptateur en premier", "it": "Inizia o abilita prima l'adattatore", "es": "Comience o habilite el adaptador primero", "pl": "Najpierw włącz lub włącz adapter"},
|
||||
"debounce": { "en": "De-bounce interval(ms)", "de": "Entprellzeit(ms)", "ru": "Минимальный интервал(ms)", "pt": "Intervalo de desvio (ms)", "nl": "De-bounce interval (ms)", "fr": "Intervalle de rebond (ms)", "it": "Intervallo di rimbalzo (ms)", "es": "Intervalo de rebote (ms)", "pl": "Interwał odbicia (ms)"},
|
||||
"log changes interval(s)": { "en": "Log unchanged values any(s)", "de": "Gleiche Werte aufzeichnen(s)", "ru": "Запись неизменённых значений каждые (сек)", "pt": "Registre valores inalterados qualquer (s)", "nl": "Log onveranderde waarden voor elke", "fr": "Consigner les valeurs inchangées any (s)", "it": "Registra valori invariati nessuno (i)", "es": "Registre los valores sin modificar cualquier (s)", "pl": "Zaloguj niezmienione wartości dowolne (s)"},
|
||||
"log changes minimal delta": { "en": "Minimum difference from last value to log", "de": "Minimale Abweichung vom letzten Wert für Aufzeichnung", "ru": "Минимальная разница с последним записанным значением", "pt": "Diferença mínima do último valor ao log", "nl": "Minimaal verschil van laatste waarde tot log", "fr": "Différence minimale de la dernière valeur à la notation", "it": "Differenza minima dall'ultimo valore da registrare", "es": "Diferencia mínima desde el último valor para registrar", "pl": "Minimalna różnica od ostatniej wartości do dziennika"},
|
||||
"0 = disable delta check": { "en": "0 = disable delta check", "de": "0 = Abweichungsprüfung deaktivieren", "ru": "0 = не проверять минимальное изменение", "pt": "0 = desativar o cheque delta", "nl": "0 = delta-controle uitschakelen", "fr": "0 = désactiver le contrôle delta", "it": "0 = disabilita il controllo delta", "es": "0 = deshabilitar la verificación delta", "pl": "0 = wyłącz kontrolę delta"},
|
||||
"0 = disable": { "en": "0 = disable", "de": "0 = Deaktivieren", "ru": "0 = не активно", "pt": "0 = desativar", "nl": "0 = uitschakelen", "fr": "0 = désactiver", "it": "0 = disabilita", "es": "0 = desactivar", "pl": "0 = wyłącz"},
|
||||
"DB settings": { "en": "DB settings", "de": "DB Einstellungen", "ru": "Настройки соединения с DB", "pt": "Configurações de banco de dados", "nl": "DB-instellingen", "fr": "Paramètres DB", "it": "Impostazioni DB", "es": "Configuración de DB", "pl": "Ustawienia DB"},
|
||||
"Default settings": { "en": "Default settings", "de": "Default Einstellungen", "ru": "Настройки по умолчанию", "pt": "Configurações padrão", "nl": "Standaard instellingen", "fr": "Paramètres par défaut", "it": "Impostazioni predefinite", "es": "Configuración por defecto", "pl": "Ustawienia domyślne"},
|
||||
"retention": { "en": "Storage retention", "de": "Storage Vorhaltezeit", "ru": "Время хранения в базе", "pt": "Retenção de armazenamento", "nl": "Bewaring van opslag", "fr": "Rétention de stockage", "it": "Conservazione dello spazio", "es": "Retención de almacenamiento", "pl": "Zatrzymanie przechowywania"},
|
||||
"keep forever": { "en": "keep forever", "de": "keine automatische Löschung", "ru": "хранить вечно", "pt": "mantenha para sempre", "nl": "blijf voor altijd", "fr": "garde pour toujours", "it": "tienilo per sempre", "es": "mantener para siempre", "pl": "zachowaj na zawsze"},
|
||||
"2 years": { "en": "2 years", "de": "2 Jahre", "ru": "2 года", "pt": "2 anos", "nl": "2 jaar", "fr": "2 ans", "it": "2 anni", "es": "2 años", "pl": "2 lata"},
|
||||
"1 year": { "en": "1 year", "de": "1 Jahr", "ru": "1 год", "pt": "1 ano", "nl": "1 jaar", "fr": "1 an", "it": "1 anno", "es": "1 año", "pl": "1 rok"},
|
||||
"6 months": { "en": "6 months", "de": "6 Monate", "ru": "6 месяцев", "pt": "6 meses", "nl": "6 maanden", "fr": "6 mois", "it": "6 mesi", "es": "6 meses", "pl": "6 miesięcy"},
|
||||
"3 months": { "en": "3 months", "de": "3 Monate", "ru": "3 месяца", "pt": "3 meses", "nl": "3 maanden", "fr": "3 mois", "it": "3 mesi", "es": "3 meses", "pl": "3 miesiące"},
|
||||
"1 months": { "en": "1 months", "de": "1 Monat", "ru": "1 месяц", "pt": "1 mês", "nl": "1 maanden", "fr": "1 mois", "it": "1 mese", "es": "1 mes", "pl": "1 miesiąc"},
|
||||
"2 weeks": { "en": "2 weeks", "de": "2 Wochen", "ru": "2 недели", "pt": "2 semanas", "nl": "2 weken", "fr": "2 semaines", "it": "2 settimane", "es": "2 semanas", "pl": "2 tygodnie"},
|
||||
"1 week": { "en": "1 week", "de": "1 Woche", "ru": "1 неделя", "pt": "1 semana", "nl": "1 week", "fr": "1 semaine", "it": "1 settimana", "es": "1 semana", "pl": "1 tydzień"},
|
||||
"5 days": { "en": "5 days", "de": "5 Tage", "ru": "5 дней", "pt": "5 dias", "nl": "5 dagen", "fr": "5 jours", "it": "5 giorni", "es": "5 dias", "pl": "5 dni"},
|
||||
"3 days": { "en": "3 days", "de": "3 Tage", "ru": "3 дня", "pt": "3 dias", "nl": "3 dagen", "fr": "3 jours", "it": "3 giorni", "es": "3 días", "pl": "3 dni"},
|
||||
"1 day": { "en": "1 day", "de": "1 Tag", "ru": "1 день", "pt": "1 dia", "nl": "1 dag", "fr": "Un jour", "it": "1 giorno", "es": "1 día", "pl": "1 dzień"},
|
||||
"SQL history adapter settings": { "en": "SQL history adapter settings", "de": "SQL history adapter Einstellungen", "ru": "Настройки профайлера в SQL базу данных", "pt": "Configurações do adaptador de histórico SQL", "nl": "Instellingen voor SQL-geschiedenisadapter", "fr": "Paramètres de l'adaptateur d'historique SQL", "it": "Impostazioni della scheda cronologia SQL", "es": "Configuración del adaptador de historial SQL", "pl": "Ustawienia adaptera historii SQL"},
|
||||
"DB settings:": { "en": "DB settings", "de": "DB Einstellungen", "ru": "DB settings", "pt": "Configurações de banco de dados", "nl": "DB-instellingen", "fr": "Paramètres de base de données", "it": "Impostazioni DB", "es": "Configuración de DB", "pl": "Ustawienia DB"},
|
||||
"DB Type": { "en": "DB Type", "de": "DB Typ", "ru": "DB Type", "pt": "DB Type", "nl": "DB Type", "fr": "Type de DB", "it": "Tipo di DB", "es": "Tipo de DB", "pl": "Typ DB"},
|
||||
"Host": { "en": "Host", "de": "Host", "ru": "Хост", "pt": "Hospedeiro", "nl": "Host", "fr": "Hôte", "it": "Ospite", "es": "Anfitrión", "pl": "Gospodarz"},
|
||||
"DB Name": { "en": "Database name", "de": "Datenbankname", "ru": "Имя базы данных", "pt": "Nome do banco de dados", "nl": "Database naam", "fr": "Nom de la base de données", "it": "Nome del database", "es": "Nombre de la base de datos", "pl": "Nazwa bazy danych"},
|
||||
"Port": { "en": "Port", "de": "Port", "ru": "Порт", "pt": "Porta", "nl": "Haven", "fr": "Port", "it": "Porta", "es": "Puerto", "pl": "Port"},
|
||||
"User": { "en": "User", "de": "Login", "ru": "Пользователь", "pt": "Do utilizador", "nl": "Gebruiker", "fr": "Utilisateur", "it": "Utente", "es": "Usuario", "pl": "Użytkownik"},
|
||||
"Password": { "en": "Password", "de": "Kennwort", "ru": "Пароль", "pt": "Senha", "nl": "Wachtwoord", "fr": "Mot de passe", "it": "Parola d'ordine", "es": "Contraseña", "pl": "Hasło"},
|
||||
"Password confirm": { "en": "Password confirm", "de": "Kennwort-Wiederholung", "ru": "Подтверждение пароля", "pt": "Confirmação de senha", "nl": "Wachtwoord bevestigen", "fr": "Confirmer le mot de passe", "it": "Conferma la password", "es": "Contraseña confirmada", "pl": "Potwierdź hasło"},
|
||||
"File for sqlite:": { "en": "File for sqlite", "de": "Datei für sqlite", "ru": "Файл для sqlite", "pt": "Arquivo para sqlite", "nl": "Bestand voor sqlite", "fr": "Fichier pour sqlite", "it": "File per sqlite", "es": "Archivo para sqlite", "pl": "Plik dla sqlite"},
|
||||
"Encrypt:": { "en": "Encrypt", "de": "Verschlüsseln", "ru": "Шифрование", "pt": "Criptografar", "nl": "versleutelen", "fr": "Crypter", "it": "Encrypt", "es": "Encriptar", "pl": "Szyfruj"},
|
||||
"Test connection": { "en": "Test connection", "de": "Verbindung testen", "ru": "Проверить соединение", "pt": "Conexão de teste", "nl": "Test verbinding", "fr": "Test de connexion", "it": "Connessione di prova", "es": "Conexión de prueba", "pl": "Testuj połączenie"},
|
||||
"requestInterval": { "en": "Pause between requests(ms)", "de": "Intervall zwischen DB Anfragen(ms)", "ru": "Пауза между запросами к базе", "pt": "Pausa entre solicitações (ms)", "nl": "Pauzeren tussen verzoeken (ms)", "fr": "Pause entre les demandes (ms)", "it": "Pausa tra le richieste (ms)", "es": "Pausa entre solicitudes (ms)", "pl": "Wstrzymaj między żądaniami (ms)"},
|
||||
"Round real to:": { "en": "Round real to", "de": "Aufrunden auf: ", "ru": "Округлять до", "pt": "Round real to", "nl": "Rond echt naar", "fr": "Rond réel à", "it": "Round reale a", "es": "Redondo real para", "pl": "Runda prawdziwa do"},
|
||||
"Password confirmation is not equal with password!": {"en": "Password confirmation is not equal with password!", "de": "Kennwort-Bestätigung ist nicht gleich mit dem Kennwort!", "ru": "Подтверждение пароля не совпадает с паролем!", "pt": "A confirmação da senha não é igual com a senha!", "nl": "Wachtwoordbevestiging is niet gelijk aan wachtwoord!", "fr": "La confirmation du mot de passe n'est pas égale au mot de passe!", "it": "La conferma della password non è uguale alla password!", "es": "La confirmación de la contraseña no es igual a la contraseña!", "pl": "Potwierdzenie hasła nie jest równe hasłu!"},
|
||||
"Input path with the file name.": { "en": "E.g. /opt/sqlite/data.db", "de": "Z.B. /opt/sqlite/data.db", "ru": "Например /opt/sqlite/data.db", "pt": "Por exemplo. /opt/sqlite/data.db", "nl": "Bijv. /opt/sqlite/data.db", "fr": "Par exemple. /opt/sqlite/data.db", "it": "Per esempio. /opt/sqlite/data.db", "es": "P.ej. /opt/sqlite/data.db", "pl": "Na przykład. /opt/sqlite/data.db"},
|
||||
"Are you sure? All data will be dropped.": { "en": "Are you sure? All data will be dropped.", "de": "Sind Sie sicher? ALLE Daten werden geöscht.", "ru": "Вы уверенны? Все данные в базе будут удалены.", "pt": "Você tem certeza? Todos os dados serão descartados.", "nl": "Weet je het zeker? Alle gegevens worden verwijderd.", "fr": "Êtes-vous sûr? Toutes les données seront supprimées.", "it": "Sei sicuro? Tutti i dati verranno eliminati.", "es": "¿Estás seguro? Todos los datos serán eliminados.", "pl": "Jesteś pewny? Wszystkie dane zostaną usunięte."},
|
||||
"Reset DB": { "en": "Reset DB", "de": "Alle Daten in DB löschen", "ru": "Сбросить DB", "pt": "Redefinir DB", "nl": "Stel DB opnieuw in", "fr": "Reset DB", "it": "Ripristina DB", "es": "Restablecer DB", "pl": "Zresetuj DB"},
|
||||
"Ok": { "en": "Ok", "de": "Ok", "ru": "Ok", "pt": "Está bem", "nl": "OK", "fr": "D'accord", "it": "Ok", "es": "De acuerdo", "pl": "Ok"},
|
||||
"Allow parallel requests:": { "en": "Allow parallel requests", "de": "Parallelanfragen erlauben", "ru": "Разрешить параллельные запросы к базе", "pt": "Permitir pedidos paralelos", "nl": "Sta parallelle verzoeken toe", "fr": "Autoriser les demandes parallèles", "it": "Consenti richieste parallele", "es": "Permitir solicitudes paralelas", "pl": "Pozwól na równoległe żądania"},
|
||||
"Write NULL values on start/stop boundaries:": {
|
||||
"en": "Write NULL values on start/stop boundaries:",
|
||||
"de": "Schreibe NULL-Werte an Start- / Stop-Grenzen:",
|
||||
"ru": "Запись значений NULL на границах начала / остановки:",
|
||||
"pt": "Escreva valores NULL nos limites de início / parada:",
|
||||
"nl": "Schrijf NULL-waarden op start / stop-grenzen:",
|
||||
"fr": "Écrire des valeurs NULL sur les limites de démarrage / arrêt:",
|
||||
"it": "Scrivi valori NULL sui limiti di avvio / arresto:",
|
||||
"es": "Escribe valores NULL en los límites de inicio / finalización:",
|
||||
"pl": "Napisz wartości NULL na granicach start / stop:"
|
||||
}
|
||||
};
|
||||
31
appveyor.yml
Normal file
31
appveyor.yml
Normal file
@@ -0,0 +1,31 @@
|
||||
version: 'test-{build}'
|
||||
os: Visual Studio 2013
|
||||
environment:
|
||||
matrix:
|
||||
- nodejs_version: '4'
|
||||
- nodejs_version: '6'
|
||||
- nodejs_version: '8'
|
||||
- nodejs_version: '10'
|
||||
platform:
|
||||
- x86
|
||||
- x64
|
||||
clone_folder: 'c:\projects\%APPVEYOR_PROJECT_NAME%'
|
||||
services:
|
||||
- mssql2014
|
||||
- mysql
|
||||
- postgresql
|
||||
install:
|
||||
- ps: 'Install-Product node $env:nodejs_version $env:platform'
|
||||
- ps: '$NpmVersion = (npm -v).Substring(0,1)'
|
||||
- ps: 'if($NpmVersion -eq 5) { npm install -g npm@5 }'
|
||||
- ps: npm --version
|
||||
- npm install
|
||||
- npm install winston@2.3.1
|
||||
- 'npm install https://git.spacen.net/yunkong2/yunkong2.js-controller/tarball/master --production'
|
||||
test_script:
|
||||
- echo %cd%
|
||||
- node --version
|
||||
- npm --version
|
||||
- ps: Start-Sleep -s 15
|
||||
- npm test
|
||||
build: 'off'
|
||||
401
gulpfile.js
Normal file
401
gulpfile.js
Normal file
@@ -0,0 +1,401 @@
|
||||
'use strict';
|
||||
|
||||
var gulp = require('gulp');
|
||||
var fs = require('fs');
|
||||
var pkg = require('./package.json');
|
||||
var iopackage = require('./io-package.json');
|
||||
var version = (pkg && pkg.version) ? pkg.version : iopackage.common.version;
|
||||
/*var appName = getAppName();
|
||||
|
||||
function getAppName() {
|
||||
var parts = __dirname.replace(/\\/g, '/').split('/');
|
||||
return parts[parts.length - 1].split('.')[0].toLowerCase();
|
||||
}
|
||||
*/
|
||||
const fileName = 'words.js';
|
||||
var languages = {
|
||||
en: {},
|
||||
de: {},
|
||||
ru: {},
|
||||
pt: {},
|
||||
nl: {},
|
||||
fr: {},
|
||||
it: {},
|
||||
es: {},
|
||||
pl: {}
|
||||
};
|
||||
|
||||
function lang2data(lang, isFlat) {
|
||||
var str = isFlat ? '' : '{\n';
|
||||
var count = 0;
|
||||
for (var w in lang) {
|
||||
if (lang.hasOwnProperty(w)) {
|
||||
count++;
|
||||
if (isFlat) {
|
||||
str += (lang[w] === '' ? (isFlat[w] || w) : lang[w]) + '\n';
|
||||
} else {
|
||||
var key = ' "' + w.replace(/"/g, '\\"') + '": ';
|
||||
str += key + '"' + lang[w].replace(/"/g, '\\"') + '",\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!count) return isFlat ? '' : '{\n}';
|
||||
if (isFlat) {
|
||||
return str;
|
||||
} else {
|
||||
return str.substring(0, str.length - 2) + '\n}';
|
||||
}
|
||||
}
|
||||
|
||||
function readWordJs(src) {
|
||||
try {
|
||||
var words;
|
||||
if (fs.existsSync(src + 'js/' + fileName)) {
|
||||
words = fs.readFileSync(src + 'js/' + fileName).toString();
|
||||
} else {
|
||||
words = fs.readFileSync(src + fileName).toString();
|
||||
}
|
||||
|
||||
var lines = words.split(/\r\n|\r|\n/g);
|
||||
var i = 0;
|
||||
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');
|
||||
var resultFunc = new Function('return ' + words + ';');
|
||||
|
||||
return resultFunc();
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
function padRight(text, totalLength) {
|
||||
return text + (text.length < totalLength ? new Array(totalLength - text.length).join(' ') : '');
|
||||
}
|
||||
function writeWordJs(data, src) {
|
||||
var text = '// DO NOT EDIT THIS FILE!!! IT WILL BE AUTOMATICALLY GENERATED FROM src/i18n\n';
|
||||
text += '/*global systemDictionary:true */\n';
|
||||
text += '\'use strict\';\n\n';
|
||||
|
||||
text += 'systemDictionary = {\n';
|
||||
for (var word in data) {
|
||||
if (data.hasOwnProperty(word)) {
|
||||
text += ' ' + padRight('"' + word.replace(/"/g, '\\"') + '": {', 50);
|
||||
var line = '';
|
||||
for (var lang in data[word]) {
|
||||
if (data[word].hasOwnProperty(lang)) {
|
||||
line += '"' + lang + '": "' + padRight(data[word][lang].replace(/"/g, '\\"') + '",', 50) + ' ';
|
||||
}
|
||||
}
|
||||
if (line) {
|
||||
line = line.trim();
|
||||
line = line.substring(0, line.length - 1);
|
||||
}
|
||||
text += line + '},\n';
|
||||
}
|
||||
}
|
||||
text = text.replace(/},\n$/, '}\n');
|
||||
text += '};';
|
||||
|
||||
if (fs.existsSync(src + 'js/' + fileName)) {
|
||||
fs.writeFileSync(src + 'js/' + fileName, text);
|
||||
} else {
|
||||
fs.writeFileSync(src + '' + fileName, text);
|
||||
}
|
||||
}
|
||||
|
||||
const EMPTY = '';
|
||||
|
||||
function words2languages(src) {
|
||||
var langs = Object.assign({}, languages);
|
||||
var data = readWordJs(src);
|
||||
if (data) {
|
||||
for (var word in data) {
|
||||
if (data.hasOwnProperty(word)) {
|
||||
for (var lang in data[word]) {
|
||||
if (data[word].hasOwnProperty(lang)) {
|
||||
langs[lang][word] = data[word][lang];
|
||||
// pre-fill all other languages
|
||||
for (var j in langs) {
|
||||
if (langs.hasOwnProperty(j)) {
|
||||
langs[j][word] = langs[j][word] || EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!fs.existsSync(src + 'i18n/')) {
|
||||
fs.mkdirSync(src + 'i18n/');
|
||||
}
|
||||
for (var l in langs) {
|
||||
if (!langs.hasOwnProperty(l)) continue;
|
||||
var keys = Object.keys(langs[l]);
|
||||
//keys.sort();
|
||||
var obj = {};
|
||||
for (var k = 0; k < keys.length; k++) {
|
||||
obj[keys[k]] = langs[l][keys[k]];
|
||||
}
|
||||
if (!fs.existsSync(src + 'i18n/' + l)) {
|
||||
fs.mkdirSync(src + 'i18n/' + l);
|
||||
}
|
||||
|
||||
fs.writeFileSync(src + 'i18n/' + l + '/translations.json', lang2data(obj));
|
||||
}
|
||||
} else {
|
||||
console.error('Cannot read or parse ' + fileName);
|
||||
}
|
||||
}
|
||||
function words2languagesFlat(src) {
|
||||
var langs = Object.assign({}, languages);
|
||||
var data = readWordJs(src);
|
||||
if (data) {
|
||||
for (var word in data) {
|
||||
if (data.hasOwnProperty(word)) {
|
||||
for (var lang in data[word]) {
|
||||
if (data[word].hasOwnProperty(lang)) {
|
||||
langs[lang][word] = data[word][lang];
|
||||
// pre-fill all other languages
|
||||
for (var j in langs) {
|
||||
if (langs.hasOwnProperty(j)) {
|
||||
langs[j][word] = langs[j][word] || EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var keys = Object.keys(langs.en);
|
||||
//keys.sort();
|
||||
for (var l in langs) {
|
||||
if (!langs.hasOwnProperty(l)) continue;
|
||||
var obj = {};
|
||||
for (var 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 (var 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) {
|
||||
var dirs = fs.readdirSync(src + 'i18n/');
|
||||
var langs = {};
|
||||
var bigOne = {};
|
||||
var order = Object.keys(languages);
|
||||
dirs.sort(function (a, b) {
|
||||
var posA = order.indexOf(a);
|
||||
var posB = order.indexOf(b);
|
||||
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;
|
||||
}
|
||||
});
|
||||
var keys = fs.readFileSync(src + 'i18n/flat.txt').toString().split('\n');
|
||||
|
||||
for (var l = 0; l < dirs.length; l++) {
|
||||
if (dirs[l] === 'flat.txt') continue;
|
||||
var lang = dirs[l];
|
||||
var values = fs.readFileSync(src + 'i18n/' + lang + '/flat.txt').toString().split('\n');
|
||||
langs[lang] = {};
|
||||
keys.forEach(function (word, i) {
|
||||
langs[lang][word] = values[i].replace(/<\/ i>/g, '</i>').replace(/<\/ b>/g, '</b>').replace(/<\/ span>/g, '</span>').replace(/% s/g, ' %s');
|
||||
});
|
||||
|
||||
var words = langs[lang];
|
||||
for (var word in words) {
|
||||
if (words.hasOwnProperty(word)) {
|
||||
bigOne[word] = bigOne[word] || {};
|
||||
if (words[word] !== EMPTY) {
|
||||
bigOne[word][lang] = words[word];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// read actual words.js
|
||||
var aWords = readWordJs();
|
||||
|
||||
var temporaryIgnore = ['pt', 'fr', 'nl', 'flat.txt'];
|
||||
if (aWords) {
|
||||
// Merge words together
|
||||
for (var 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) {
|
||||
var dirs = fs.readdirSync(src + 'i18n/');
|
||||
var langs = {};
|
||||
var bigOne = {};
|
||||
var order = Object.keys(languages);
|
||||
dirs.sort(function (a, b) {
|
||||
var posA = order.indexOf(a);
|
||||
var posB = order.indexOf(b);
|
||||
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;
|
||||
}
|
||||
});
|
||||
for (var l = 0; l < dirs.length; l++) {
|
||||
if (dirs[l] === 'flat.txt') continue;
|
||||
var lang = dirs[l];
|
||||
langs[lang] = fs.readFileSync(src + 'i18n/' + lang + '/translations.json').toString();
|
||||
langs[lang] = JSON.parse(langs[lang]);
|
||||
var words = langs[lang];
|
||||
for (var word in words) {
|
||||
if (words.hasOwnProperty(word)) {
|
||||
bigOne[word] = bigOne[word] || {};
|
||||
if (words[word] !== EMPTY) {
|
||||
bigOne[word][lang] = words[word];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// read actual words.js
|
||||
var aWords = readWordJs();
|
||||
|
||||
var temporaryIgnore = ['pt', 'fr', 'nl', 'it'];
|
||||
if (aWords) {
|
||||
// Merge words together
|
||||
for (var 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);
|
||||
}
|
||||
|
||||
gulp.task('adminWords2languages', function (done) {
|
||||
words2languages('./admin/');
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task('adminWords2languagesFlat', function (done) {
|
||||
words2languagesFlat('./admin/');
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task('adminLanguagesFlat2words', function (done) {
|
||||
languagesFlat2words('./admin/');
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task('adminLanguages2words', function (done) {
|
||||
languages2words('./admin/');
|
||||
done();
|
||||
});
|
||||
|
||||
|
||||
gulp.task('updatePackages', function (done) {
|
||||
iopackage.common.version = pkg.version;
|
||||
iopackage.common.news = iopackage.common.news || {};
|
||||
if (!iopackage.common.news[pkg.version]) {
|
||||
var news = iopackage.common.news;
|
||||
var newNews = {};
|
||||
|
||||
newNews[pkg.version] = {
|
||||
en: 'news',
|
||||
de: 'neues',
|
||||
ru: 'новое'
|
||||
};
|
||||
iopackage.common.news = Object.assign(newNews, news);
|
||||
}
|
||||
fs.writeFileSync('io-package.json', JSON.stringify(iopackage, null, 4));
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task('updateReadme', function (done) {
|
||||
var readme = fs.readFileSync('README.md').toString();
|
||||
var pos = readme.indexOf('## Changelog\n');
|
||||
if (pos !== -1) {
|
||||
var readmeStart = readme.substring(0, pos + '## Changelog\n'.length);
|
||||
var readmeEnd = readme.substring(pos + '## Changelog\n'.length);
|
||||
|
||||
if (readme.indexOf(version) === -1) {
|
||||
var timestamp = new Date();
|
||||
var date = timestamp.getFullYear() + '-' +
|
||||
('0' + (timestamp.getMonth() + 1).toString(10)).slice(-2) + '-' +
|
||||
('0' + (timestamp.getDate()).toString(10)).slice(-2);
|
||||
|
||||
var news = '';
|
||||
if (iopackage.common.news && iopackage.common.news[pkg.version]) {
|
||||
news += '* ' + iopackage.common.news[pkg.version].en;
|
||||
}
|
||||
|
||||
fs.writeFileSync('README.md', readmeStart + '### ' + version + ' (' + date + ')\n' + (news ? news + '\n\n' : '\n') + readmeEnd);
|
||||
}
|
||||
}
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task('default', ['updatePackages', 'updateReadme']);
|
||||
95
io-package.json
Normal file
95
io-package.json
Normal file
@@ -0,0 +1,95 @@
|
||||
{
|
||||
"common": {
|
||||
"name": "sql",
|
||||
"title": "SQL History",
|
||||
"titleLang": {
|
||||
"en": "SQL logging"
|
||||
},
|
||||
"desc": {
|
||||
"en": "Logging of states into SQL DB"
|
||||
},
|
||||
"version": "1.9.2",
|
||||
"mode": "daemon",
|
||||
"platform": "Node.js",
|
||||
"loglevel": "info",
|
||||
"messagebox": true,
|
||||
"subscribe": "messagebox",
|
||||
"keywords": ["charts", "sql", "logging", "graphs", "archive"],
|
||||
"preserveSettings": "custom",
|
||||
"supportCustoms": true,
|
||||
"getHistory": true,
|
||||
"enabled": true,
|
||||
"stopBeforeUpdate": true,
|
||||
"materialize": true,
|
||||
"authors": [
|
||||
"bluefox <dogafox@gmail.com>",
|
||||
"Apollon77 <ingo@fischer-ka.de>"
|
||||
],
|
||||
"license": "MIT",
|
||||
"readme": "https://git.spacen.net/yunkong2/yunkong2.sql/blob/master/README.md",
|
||||
"icon": "sql.png",
|
||||
"extIcon": "https://git.spacen.net/yunkong2/yunkong2.sql/raw/master/admin/sql.png",
|
||||
"type": "storage",
|
||||
"dependencies": [{"js-controller": ">=0.12.0","admin": ">=1.6.10"}],
|
||||
"supportStopInstance": 2000,
|
||||
"config":{
|
||||
"minWidth": 570,
|
||||
"width ": 435,
|
||||
"minHeight": 200,
|
||||
"height": 540
|
||||
}
|
||||
},
|
||||
"native": {
|
||||
"connLink": "",
|
||||
"debounce": 1000,
|
||||
"retention": 31536000,
|
||||
"host": "localhost",
|
||||
"port": 0,
|
||||
"user": "",
|
||||
"password": "",
|
||||
"dbtype": "sqlite",
|
||||
"fileName": "sqlite.db",
|
||||
"requestInterval": 0,
|
||||
"encrypt": false,
|
||||
"round": 4,
|
||||
"dbname": "yunkong2",
|
||||
"multiRequests": true,
|
||||
"changesRelogInterval": 0,
|
||||
"changesMinDelta": 0,
|
||||
"writeNulls": true
|
||||
},
|
||||
"instanceObjects": [
|
||||
{
|
||||
"_id": "info",
|
||||
"type": "channel",
|
||||
"common": {
|
||||
"name": "Information"
|
||||
},
|
||||
"native": {}
|
||||
},
|
||||
{
|
||||
"_id": "info.connection",
|
||||
"type": "state",
|
||||
"common": {
|
||||
"role": "indicator.connected",
|
||||
"name": "If connected to DB",
|
||||
"type": "boolean",
|
||||
"read": true,
|
||||
"write": false,
|
||||
"def": false
|
||||
},
|
||||
"native": {}
|
||||
}
|
||||
],
|
||||
"objects": [
|
||||
{
|
||||
"_id": "_design/custom",
|
||||
"language": "javascript",
|
||||
"views": {
|
||||
"state": {
|
||||
"map": "function(doc) { if (doc.type==='state' && (doc.common.custom || doc.common.history)) emit(doc._id, doc.common.custom || doc.common.history) }"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
476
lib/aggregate.js
Normal file
476
lib/aggregate.js
Normal file
@@ -0,0 +1,476 @@
|
||||
/* jshint -W097 */// jshint strict:false
|
||||
/*jslint node: true */
|
||||
"use strict";
|
||||
// THIS file should be identical with sql and history adapter's one
|
||||
|
||||
function initAggregate(options) {
|
||||
|
||||
//step; // 1 Step is 1 second
|
||||
if (options.step === null) {
|
||||
options.step = (options.end - options.start) / options.count;
|
||||
}
|
||||
|
||||
// Limit 2000
|
||||
if ((options.end - options.start) / options.step > options.limit) {
|
||||
options.step = (options.end - options.start) / options.limit;
|
||||
}
|
||||
|
||||
options.maxIndex = Math.ceil(((options.end - options.start) / options.step) - 1);
|
||||
options.result = [];
|
||||
options.averageCount = [];
|
||||
options.aggregate = options.aggregate || 'minmax';
|
||||
options.overallLength = 0;
|
||||
|
||||
// pre-fill the result with timestamps (add one before start and one after end)
|
||||
for (var i = 0; i <= options.maxIndex + 2; i++){
|
||||
|
||||
options.result[i] = {
|
||||
val: {ts: null, val: null},
|
||||
max: {ts: null, val: null},
|
||||
min: {ts: null, val: null},
|
||||
start: {ts: null, val: null},
|
||||
end: {ts: null, val: null}
|
||||
};
|
||||
|
||||
if (options.aggregate === 'average') options.averageCount[i] = 0;
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
function aggregation(options, data) {
|
||||
var index;
|
||||
var preIndex;
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
if (!data[i]) continue;
|
||||
if (typeof data[i].ts !== 'number') data[i].ts = parseInt(data[i].ts, 10);
|
||||
if (data[i].ts < 946681200000) data[i].ts *= 1000;
|
||||
|
||||
preIndex = Math.floor((data[i].ts - options.start) / options.step);
|
||||
|
||||
// store all border values
|
||||
if (preIndex < 0) {
|
||||
index = 0;
|
||||
} else if (preIndex > options.maxIndex) {
|
||||
index = options.maxIndex + 2;
|
||||
} else {
|
||||
index = preIndex + 1;
|
||||
}
|
||||
options.overallLength++;
|
||||
|
||||
if (!options.result[index]) {
|
||||
console.error('Cannot find index ' + index);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (options.aggregate === 'max') {
|
||||
if (!options.result[index].val.ts) options.result[index].val.ts = Math.round(options.start + (((index - 1) + 0.5) * options.step));
|
||||
if (options.result[index].val.val === null || options.result[index].val.val < data[i].val) options.result[index].val.val = data[i].val;
|
||||
} else if (options.aggregate === 'min') {
|
||||
if (!options.result[index].val.ts) options.result[index].val.ts = Math.round(options.start + (((index - 1) + 0.5) * options.step));
|
||||
if (options.result[index].val.val === null || options.result[index].val.val > data[i].val) options.result[index].val.val = data[i].val;
|
||||
} else if (options.aggregate === 'average') {
|
||||
if (!options.result[index].val.ts) options.result[index].val.ts = Math.round(options.start + (((index - 1) + 0.5) * options.step));
|
||||
options.result[index].val.val += parseFloat(data[i].val);
|
||||
options.averageCount[index]++;
|
||||
} else if (options.aggregate === 'total') {
|
||||
if (!options.result[index].val.ts) options.result[index].val.ts = Math.round(options.start + (((index - 1) + 0.5) * options.step));
|
||||
options.result[index].val.val += parseFloat(data[i].val);
|
||||
} else if (options.aggregate === 'minmax') {
|
||||
if (options.result[index].min.ts === null) {
|
||||
options.result[index].min.ts = data[i].ts;
|
||||
options.result[index].min.val = data[i].val;
|
||||
|
||||
options.result[index].max.ts = data[i].ts;
|
||||
options.result[index].max.val = data[i].val;
|
||||
|
||||
options.result[index].start.ts = data[i].ts;
|
||||
options.result[index].start.val = data[i].val;
|
||||
|
||||
options.result[index].end.ts = data[i].ts;
|
||||
options.result[index].end.val = data[i].val;
|
||||
} else {
|
||||
if (data[i].val !== null) {
|
||||
if (data[i].val > options.result[index].max.val) {
|
||||
options.result[index].max.ts = data[i].ts;
|
||||
options.result[index].max.val = data[i].val;
|
||||
} else if (data[i].val < options.result[index].min.val) {
|
||||
options.result[index].min.ts = data[i].ts;
|
||||
options.result[index].min.val = data[i].val;
|
||||
}
|
||||
if (data[i].ts > options.result[index].end.ts) {
|
||||
options.result[index].end.ts = data[i].ts;
|
||||
options.result[index].end.val = data[i].val;
|
||||
}
|
||||
} else {
|
||||
if (data[i].ts > options.result[index].end.ts) {
|
||||
options.result[index].end.ts = data[i].ts;
|
||||
options.result[index].end.val = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {result: options.result, step: options.step, sourceLength: data.length} ;
|
||||
}
|
||||
|
||||
function finishAggregation(options) {
|
||||
if (options.aggregate === 'minmax') {
|
||||
for (var ii = options.result.length - 1; ii >= 0; ii--) {
|
||||
// no one value in this period
|
||||
if (options.result[ii].start.ts === null) {
|
||||
options.result.splice(ii, 1);
|
||||
} else {
|
||||
// just one value in this period: max == min == start == end
|
||||
if (options.result[ii].start.ts === options.result[ii].end.ts) {
|
||||
options.result[ii] = {
|
||||
ts: options.result[ii].start.ts,
|
||||
val: options.result[ii].start.val
|
||||
};
|
||||
} else
|
||||
if (options.result[ii].min.ts === options.result[ii].max.ts) {
|
||||
// if just 2 values: start == min == max, end
|
||||
if (options.result[ii].start.ts === options.result[ii].min.ts ||
|
||||
options.result[ii].end.ts === options.result[ii].min.ts) {
|
||||
options.result.splice(ii + 1, 0, {
|
||||
ts: options.result[ii].end.ts,
|
||||
val: options.result[ii].end.val
|
||||
});
|
||||
options.result[ii] = {
|
||||
ts: options.result[ii].start.ts,
|
||||
val: options.result[ii].start.val
|
||||
};
|
||||
} // if just 3 values: start, min == max, end
|
||||
else {
|
||||
options.result.splice(ii + 1, 0, {
|
||||
ts: options.result[ii].max.ts,
|
||||
val: options.result[ii].max.val
|
||||
});
|
||||
options.result.splice(ii + 2, 0, {
|
||||
ts: options.result[ii].end.ts,
|
||||
val: options.result[ii].end.val
|
||||
});
|
||||
options.result[ii] = {
|
||||
ts: options.result[ii].start.ts,
|
||||
val: options.result[ii].start.val
|
||||
};
|
||||
}
|
||||
} else
|
||||
if (options.result[ii].start.ts === options.result[ii].max.ts) {
|
||||
// just one value in this period: start == max, min == end
|
||||
if (options.result[ii].min.ts === options.result[ii].end.ts) {
|
||||
options.result.splice(ii + 1, 0, {
|
||||
ts: options.result[ii].end.ts,
|
||||
val: options.result[ii].end.val
|
||||
});
|
||||
options.result[ii] = {
|
||||
ts: options.result[ii].start.ts,
|
||||
val: options.result[ii].start.val
|
||||
};
|
||||
} // start == max, min, end
|
||||
else {
|
||||
options.result.splice(ii + 1, 0, {
|
||||
ts: options.result[ii].min.ts,
|
||||
val: options.result[ii].min.val
|
||||
});
|
||||
options.result.splice(ii + 2, 0, {
|
||||
ts: options.result[ii].end.ts,
|
||||
val: options.result[ii].end.val
|
||||
});
|
||||
options.result[ii] = {
|
||||
ts: options.result[ii].start.ts,
|
||||
val: options.result[ii].start.val
|
||||
};
|
||||
}
|
||||
} else
|
||||
if (options.result[ii].end.ts === options.result[ii].max.ts) {
|
||||
// just one value in this period: start == min, max == end
|
||||
if (options.result[ii].min.ts === options.result[ii].start.ts) {
|
||||
options.result.splice(ii + 1, 0, {
|
||||
ts: options.result[ii].end.ts,
|
||||
val: options.result[ii].end.val
|
||||
});
|
||||
options.result[ii] = {
|
||||
ts: options.result[ii].start.ts,
|
||||
val: options.result[ii].start.val
|
||||
};
|
||||
} // start, min, max == end
|
||||
else {
|
||||
|
||||
options.result.splice(ii + 1, 0, {
|
||||
ts: options.result[ii].min.ts,
|
||||
val: options.result[ii].min.val
|
||||
});
|
||||
options.result.splice(ii + 2, 0, {
|
||||
ts: options.result[ii].end.ts,
|
||||
val: options.result[ii].end.val
|
||||
});
|
||||
options.result[ii] = {
|
||||
ts: options.result[ii].start.ts,
|
||||
val: options.result[ii].start.val
|
||||
};
|
||||
}
|
||||
} else
|
||||
if (options.result[ii].start.ts === options.result[ii].min.ts ||
|
||||
options.result[ii].end.ts === options.result[ii].min.ts) {
|
||||
// just one value in this period: start == min, max, end
|
||||
options.result.splice(ii + 1, 0, {
|
||||
ts: options.result[ii].max.ts,
|
||||
val: options.result[ii].max.val
|
||||
});
|
||||
options.result.splice(ii + 2, 0, {
|
||||
ts: options.result[ii].end.ts,
|
||||
val: options.result[ii].end.val
|
||||
});
|
||||
options.result[ii] = {
|
||||
ts: options.result[ii].start.ts,
|
||||
val: options.result[ii].start.val
|
||||
};
|
||||
} else {
|
||||
// just one value in this period: start == min, max, end
|
||||
if (options.result[ii].max.ts > options.result[ii].min.ts) {
|
||||
options.result.splice(ii + 1, 0, {
|
||||
ts: options.result[ii].min.ts,
|
||||
val: options.result[ii].min.val
|
||||
});
|
||||
options.result.splice(ii + 2, 0, {
|
||||
ts: options.result[ii].max.ts,
|
||||
val: options.result[ii].max.val
|
||||
});
|
||||
} else {
|
||||
options.result.splice(ii + 1, 0, {
|
||||
ts: options.result[ii].max.ts,
|
||||
val: options.result[ii].max.val
|
||||
});
|
||||
options.result.splice(ii + 2, 0, {
|
||||
ts: options.result[ii].min.ts,
|
||||
val: options.result[ii].min.val
|
||||
});
|
||||
}
|
||||
options.result.splice(ii + 3, 0, {
|
||||
ts: options.result[ii].end.ts,
|
||||
val: options.result[ii].end.val
|
||||
});
|
||||
options.result[ii] = {
|
||||
ts: options.result[ii].start.ts,
|
||||
val: options.result[ii].start.val
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (options.aggregate === 'average') {
|
||||
for (var k = options.result.length - 1; k >= 0; k--) {
|
||||
if (options.result[k].val.ts) {
|
||||
options.result[k] = {
|
||||
ts: options.result[k].val.ts,
|
||||
val: (options.result[k].val.val !== null) ? Math.round(options.result[k].val.val / options.averageCount[k] * 100) / 100 : null
|
||||
};
|
||||
} else {
|
||||
// no one value in this interval
|
||||
options.result.splice(k, 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (var j = options.result.length - 1; j >= 0; j--) {
|
||||
if (options.result[j].val.ts) {
|
||||
options.result[j] = {
|
||||
ts: options.result[j].val.ts,
|
||||
val: options.result[j].val.val
|
||||
};
|
||||
} else {
|
||||
// no one value in this interval
|
||||
options.result.splice(j, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
beautify(options);
|
||||
}
|
||||
|
||||
function beautify(options) {
|
||||
var preFirstValue = null;
|
||||
var postLastValue = null;
|
||||
if (options.ignoreNull === 'true') options.ignoreNull = true; // include nulls and replace them with last value
|
||||
if (options.ignoreNull === 'false') options.ignoreNull = false; // include nulls
|
||||
if (options.ignoreNull === '0') options.ignoreNull = 0; // include nulls and replace them with 0
|
||||
if (options.ignoreNull !== true && options.ignoreNull !== false && options.ignoreNull !== 0) options.ignoreNull = false;
|
||||
|
||||
// process null values, remove points outside the span and find first points after end and before start
|
||||
for (var i = 0; i < options.result.length; i++) {
|
||||
if (options.ignoreNull !== false) {
|
||||
// if value is null
|
||||
if (options.result[i].val === null) {
|
||||
// null value must be replaced with last not null value
|
||||
if (options.ignoreNull === true) {
|
||||
// remove value
|
||||
options.result.splice(i, 1);
|
||||
i--;
|
||||
continue;
|
||||
} else {
|
||||
// null value must be replaced with 0
|
||||
options.result[i].val = options.ignoreNull;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove all not requested points
|
||||
if (options.result[i].ts < options.start) {
|
||||
preFirstValue = options.result[i].val !== null ? options.result[i] : null;
|
||||
options.result.splice(i, 1);
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
|
||||
postLastValue = options.result[i].val !== null ? options.result[i] : null;
|
||||
|
||||
if (options.result[i].ts > options.end) {
|
||||
options.result.splice(i, options.result.length - i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// check start and stop
|
||||
if (options.result.length && options.aggregate !== 'none') {
|
||||
var firstTS = options.result[0].ts;
|
||||
|
||||
if (firstTS > options.start) {
|
||||
if (preFirstValue) {
|
||||
var firstY = options.result[0].val;
|
||||
// if steps
|
||||
if (options.aggregate === 'onchange' || !options.aggregate) {
|
||||
if (preFirstValue.ts !== firstTS) {
|
||||
options.result.unshift({ts: options.start, val: preFirstValue.val});
|
||||
} else {
|
||||
if (options.ignoreNull) {
|
||||
options.result.unshift({ts: options.start, val: firstY});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (preFirstValue.ts !== firstTS) {
|
||||
if (firstY !== null) {
|
||||
// interpolate
|
||||
var y = preFirstValue.val + (firstY - preFirstValue.val) * (options.start - preFirstValue.ts) / (firstTS - preFirstValue.ts);
|
||||
options.result.unshift({ts: options.start, val: y});
|
||||
} else {
|
||||
options.result.unshift({ts: options.start, val: null});
|
||||
}
|
||||
} else {
|
||||
if (options.ignoreNull) {
|
||||
options.result.unshift({ts: options.start, val: firstY});
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (options.ignoreNull) {
|
||||
options.result.unshift({ts: options.start, val: options.result[0].val});
|
||||
} else {
|
||||
options.result.unshift({ts: options.start, val: null});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var lastTS = options.result[options.result.length - 1].ts;
|
||||
if (lastTS < options.end) {
|
||||
if (postLastValue) {
|
||||
// if steps
|
||||
if (options.aggregate === 'onchange' || !options.aggregate) {
|
||||
// if more data following, draw line to the end of chart
|
||||
if (postLastValue.ts !== lastTS) {
|
||||
options.result.push({ts: options.end, val: postLastValue.val});
|
||||
} else {
|
||||
if (options.ignoreNull) {
|
||||
options.result.push({ts: options.end, val: postLastValue.val});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (postLastValue.ts !== lastTS) {
|
||||
var lastY = options.result[options.result.length - 1].val;
|
||||
if (lastY !== null) {
|
||||
// make interpolation
|
||||
var _y = lastY + (postLastValue.val - lastY) * (options.end - lastTS) / (postLastValue.ts - lastTS);
|
||||
options.result.push({ts: options.end, val: _y});
|
||||
} else {
|
||||
options.result.push({ts: options.end, val: null});
|
||||
}
|
||||
} else {
|
||||
if (options.ignoreNull) {
|
||||
options.result.push({ts: options.end, val: postLastValue.val});
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (options.ignoreNull) {
|
||||
var lastY = options.result[options.result.length - 1].val;
|
||||
// if no more data, that means do not draw line
|
||||
options.result.push({ts: options.end, val: lastY});
|
||||
} else {
|
||||
// if no more data, that means do not draw line
|
||||
options.result.push({ts: options.end, val: null});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (options.aggregate === 'none') {
|
||||
if ((options.count) && (options.result.length > options.count)) {
|
||||
options.result = options.result.slice(0, options.count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function sendResponse(adapter, msg, options, data, startTime) {
|
||||
var aggregateData;
|
||||
if (typeof data === 'string') {
|
||||
adapter.log.error(data);
|
||||
return adapter.sendTo(msg.from, msg.command, {
|
||||
result: [],
|
||||
step: 0,
|
||||
error: data,
|
||||
sessionId: options.sessionId
|
||||
}, msg.callback);
|
||||
}
|
||||
|
||||
if (options.count && !options.start && data.length > options.count) {
|
||||
data.splice(0, data.length - options.count);
|
||||
}
|
||||
if (data[0]) {
|
||||
options.start = options.start || data[0].ts;
|
||||
|
||||
if (!options.aggregate || options.aggregate === 'onchange' || options.aggregate === 'none') {
|
||||
aggregateData = {result: data, step: 0, sourceLength: data.length};
|
||||
|
||||
// convert ack from 0/1 to false/true
|
||||
if (options.ack && aggregateData.result) {
|
||||
for (var i = 0; i < aggregateData.result.length; i++) {
|
||||
aggregateData.result[i].ack = !!aggregateData.result[i].ack;
|
||||
}
|
||||
}
|
||||
options.result = aggregateData.result;
|
||||
beautify(options);
|
||||
if ((options.aggregate === 'none') && (options.count) && (options.result.length > options.count)) {
|
||||
options.result = options.result.slice(0, options.count);
|
||||
}
|
||||
aggregateData.result = options.result;
|
||||
} else {
|
||||
initAggregate(options);
|
||||
aggregateData = aggregation(options, data);
|
||||
finishAggregation(options);
|
||||
aggregateData.result = options.result;
|
||||
}
|
||||
|
||||
adapter.log.debug('Send: ' + aggregateData.result.length + ' of: ' + aggregateData.sourceLength + ' in: ' + (new Date().getTime() - startTime) + 'ms');
|
||||
adapter.sendTo(msg.from, msg.command, {
|
||||
result: aggregateData.result,
|
||||
step: aggregateData.step,
|
||||
error: null,
|
||||
sessionId: options.sessionId
|
||||
}, msg.callback);
|
||||
} else {
|
||||
adapter.log.info('No Data');
|
||||
adapter.sendTo(msg.from, msg.command, {result: [], step: null, error: null, sessionId: options.sessionId}, msg.callback);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.sendResponse = sendResponse;
|
||||
module.exports.initAggregate = initAggregate;
|
||||
module.exports.aggregation = aggregation;
|
||||
module.exports.beautify = beautify;
|
||||
module.exports.finishAggregation = finishAggregation;
|
||||
86
lib/mssql-client.js
Normal file
86
lib/mssql-client.js
Normal file
@@ -0,0 +1,86 @@
|
||||
// Generated by CoffeeScript 1.10.0
|
||||
(function() {
|
||||
var ConnectionFactory, SQLClient, SQLClientPool, MSSQLClient, MSSQLClientPool, MSSQLConnectionFactory, mssql,
|
||||
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
|
||||
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||
hasProp = {}.hasOwnProperty,
|
||||
slice = [].slice;
|
||||
|
||||
SQLClient = require('sql-client/lib/sql-client').SQLClient;
|
||||
|
||||
SQLClientPool = require('sql-client/lib/sql-client-pool').SQLClientPool;
|
||||
|
||||
ConnectionFactory = require('sql-client/lib/connection-factory').ConnectionFactory;
|
||||
|
||||
mssql = require('mssql');
|
||||
|
||||
MSSQLConnectionFactory = (function(superClass) {
|
||||
extend(MSSQLConnectionFactory, superClass);
|
||||
|
||||
function MSSQLConnectionFactory() {
|
||||
this.execute = bind(this.execute, this);
|
||||
this.open_connection = bind(this.open_connection, this);
|
||||
return MSSQLConnectionFactory.__super__.constructor.apply(this, arguments);
|
||||
}
|
||||
|
||||
MSSQLConnectionFactory.prototype.open_connection = function(config, callback) {
|
||||
var connection;
|
||||
var pos = config.server.indexOf(':');
|
||||
if (pos != -1) {
|
||||
config.port = parseInt(config.server.substring(pos + 1), 10);
|
||||
config.server = config.server.substring(0, pos);
|
||||
}
|
||||
|
||||
return connection = new mssql.Connection(config, function (err) {
|
||||
if (err != null) {
|
||||
return callback(err);
|
||||
} else {
|
||||
return callback(null, connection);
|
||||
}
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
MSSQLConnectionFactory.prototype.execute = function(connection, sql, bindvars, callback) {
|
||||
var request = new mssql.Request(connection);
|
||||
return request.query(sql, function(err, recordset) {
|
||||
callback(err, recordset);
|
||||
});
|
||||
};
|
||||
|
||||
return MSSQLConnectionFactory;
|
||||
|
||||
})(ConnectionFactory);
|
||||
|
||||
MSSQLClient = (function(superClass) {
|
||||
extend(MSSQLClient, superClass);
|
||||
|
||||
function MSSQLClient() {
|
||||
var options;
|
||||
options = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||
MSSQLClient.__super__.constructor.apply(this, slice.call(options).concat([new MSSQLConnectionFactory()]));
|
||||
}
|
||||
|
||||
return MSSQLClient;
|
||||
|
||||
})(SQLClient);
|
||||
|
||||
MSSQLClientPool = (function(superClass) {
|
||||
extend(MSSQLClientPool, superClass);
|
||||
|
||||
function MSSQLClientPool() {
|
||||
var options;
|
||||
options = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||
MSSQLClientPool.__super__.constructor.apply(this, slice.call(options).concat([new MSSQLConnectionFactory()]));
|
||||
}
|
||||
|
||||
return MSSQLClientPool;
|
||||
|
||||
})(SQLClientPool);
|
||||
|
||||
exports.MSSQLConnectionFactory = MSSQLConnectionFactory;
|
||||
|
||||
exports.MSSQLClient = MSSQLClient;
|
||||
|
||||
exports.MSSQLClientPool = MSSQLClientPool;
|
||||
|
||||
}).call(this);
|
||||
151
lib/mssql.js
Normal file
151
lib/mssql.js
Normal file
@@ -0,0 +1,151 @@
|
||||
exports.init = function (dbname) {
|
||||
return [
|
||||
"CREATE DATABASE " + dbname + ";",
|
||||
"CREATE TABLE " + dbname + ".dbo.sources (id INTEGER NOT NULL PRIMARY KEY IDENTITY(1,1), name varchar(255));",
|
||||
"CREATE TABLE " + dbname + ".dbo.datapoints (id INTEGER NOT NULL PRIMARY KEY IDENTITY(1,1), name varchar(255), type INTEGER);",
|
||||
"CREATE TABLE " + dbname + ".dbo.ts_number (id INTEGER, ts BIGINT, val REAL, ack BIT, _from INTEGER, q INTEGER);",
|
||||
"CREATE TABLE " + dbname + ".dbo.ts_string (id INTEGER, ts BIGINT, val TEXT, ack BIT, _from INTEGER, q INTEGER);",
|
||||
"CREATE TABLE " + dbname + ".dbo.ts_bool (id INTEGER, ts BIGINT, val BIT, ack BIT, _from INTEGER, q INTEGER);"
|
||||
];
|
||||
};
|
||||
|
||||
exports.destroy = function (dbname) {
|
||||
return [
|
||||
"DROP TABLE " + dbname + ".dbo.ts_number;",
|
||||
"DROP TABLE " + dbname + ".dbo.ts_string;",
|
||||
"DROP TABLE " + dbname + ".dbo.ts_bool;",
|
||||
"DROP TABLE " + dbname + ".dbo.sources;",
|
||||
"DROP TABLE " + dbname + ".dbo.datapoints;",
|
||||
"DROP DATABASE " + dbname + ";",
|
||||
"DBCC FREEPROCCACHE;"
|
||||
];
|
||||
};
|
||||
|
||||
exports.getFirstTs = function (dbname, db) {
|
||||
return "SELECT id, MIN(ts) AS ts FROM " + dbname + ".dbo." + db + " GROUP BY id;";
|
||||
};
|
||||
|
||||
exports.insert = function (dbname, index, state, from, db) {
|
||||
if (state.val === null) state.val = 'NULL';
|
||||
else if (db === "ts_bool") state.val = state.val ? 1 : 0;
|
||||
else if (db === "ts_string") state.val = "'" + state.val.toString().replace(/'/g, '') + "'";
|
||||
|
||||
return "INSERT INTO " + dbname + ".dbo." + db + " (id, ts, val, ack, _from, q) VALUES(" + index + ", " + state.ts + ", " + state.val + ", " + (state.ack ? 1 : 0) + ", " + (from || 0) + ", " + (state.q || 0) + ");";
|
||||
};
|
||||
|
||||
exports.retention = function (dbname, index, db, retention) {
|
||||
var d = new Date();
|
||||
d.setSeconds(-retention);
|
||||
var query = "DELETE FROM " + dbname + ".dbo." + db + " WHERE";
|
||||
query += " id=" + index;
|
||||
query += " AND ts < " + d.getTime();
|
||||
query += ";";
|
||||
return query;
|
||||
};
|
||||
|
||||
exports.getIdSelect = function (dbname, name) {
|
||||
if (!name) {
|
||||
return "SELECT id, type, name FROM " + dbname + ".dbo.datapoints;";
|
||||
} else {
|
||||
return "SELECT id, type, name FROM " + dbname + ".dbo.datapoints WHERE name='" + name + "';";
|
||||
}
|
||||
};
|
||||
|
||||
exports.getIdInsert = function (dbname, name, type) {
|
||||
return "INSERT INTO " + dbname + ".dbo.datapoints (name, type) VALUES('" + name + "', " + type + ");";
|
||||
};
|
||||
|
||||
exports.getIdUpdate = function (dbname, id, type) {
|
||||
return "UPDATE " + dbname + ".dbo.datapoints SET type = " + type + " WHERE id = " + id + ";";
|
||||
};
|
||||
|
||||
exports.getFromSelect = function (dbname, from) {
|
||||
return "SELECT id FROM " + dbname + ".dbo.sources WHERE name='" + from + "';";
|
||||
};
|
||||
|
||||
exports.getFromInsert = function (dbname, from) {
|
||||
return "INSERT INTO " + dbname + ".dbo.sources (name) VALUES('" + from + "');";
|
||||
};
|
||||
|
||||
exports.getHistory = function (dbname, db, options) {
|
||||
var query = "SELECT ";
|
||||
if (!options.start && options.count) {
|
||||
query += " TOP " + options.count;
|
||||
}
|
||||
query += " ts, val" +
|
||||
(!options.id ? (", " + db + ".id as id") : "") +
|
||||
(options.ack ? ", ack" : "") +
|
||||
(options.from ? (", " + dbname + ".dbo.sources.name as 'from'") : "") +
|
||||
(options.q ? ", q" : "") + " FROM " + dbname + ".dbo." + db;
|
||||
|
||||
if (options.from) {
|
||||
query += " INNER JOIN " + dbname + ".dbo.sources ON " + dbname + ".dbo.sources.id=" + dbname + ".dbo." + db + "._from";
|
||||
}
|
||||
|
||||
var where = "";
|
||||
|
||||
if (options.id) {
|
||||
where += " " + dbname + ".dbo." + db + ".id=" + options.id;
|
||||
}
|
||||
if (options.end) {
|
||||
where += (where ? " AND" : "") + " " + dbname + ".dbo." + db + ".ts < " + options.end;
|
||||
}
|
||||
if (options.start) {
|
||||
where += (where ? " AND" : "") + " " + dbname + ".dbo." + db + ".ts >= " + options.start;
|
||||
|
||||
// add last value before start
|
||||
var subQuery;
|
||||
var subWhere;
|
||||
subQuery = " SELECT TOP 1 ts, val" +
|
||||
(!options.id ? (", " + db + ".id as id") : "") +
|
||||
(options.ack ? ", ack" : "") +
|
||||
(options.from ? (", " + dbname + ".dbo.sources.name as 'from'") : "") +
|
||||
(options.q ? ", q" : "") + " FROM " + dbname + ".dbo." + db;
|
||||
if (options.from) {
|
||||
subQuery += " INNER JOIN " + dbname + ".dbo.sources ON " + dbname + ".dbo.sources.id=" + dbname + ".dbo." + db + "._from";
|
||||
}
|
||||
subWhere = "";
|
||||
if (options.id) {
|
||||
subWhere += " " + dbname + ".dbo." + db + ".id=" + options.id;
|
||||
}
|
||||
if (options.ignoreNull) {
|
||||
//subWhere += (subWhere ? " AND" : "") + " val <> NULL";
|
||||
}
|
||||
subWhere += (subWhere ? " AND" : "") + " " + dbname + ".dbo." + db + ".ts < " + options.start;
|
||||
if (subWhere) subQuery += " WHERE " + subWhere;
|
||||
subQuery += " ORDER BY " + dbname + ".dbo." + db + ".ts DESC";
|
||||
where += " UNION SELECT * FROM (" + subQuery + ") a";
|
||||
|
||||
// add next value after end
|
||||
subQuery = " SELECT TOP 1 ts, val" +
|
||||
(!options.id ? (", " + db + ".id as id") : "") +
|
||||
(options.ack ? ", ack" : "") +
|
||||
(options.from ? (", " + dbname + ".dbo.sources.name as 'from'") : "") +
|
||||
(options.q ? ", q" : "") + " FROM " + dbname + ".dbo." + db;
|
||||
if (options.from) {
|
||||
subQuery += " INNER JOIN " + dbname + ".dbo.sources ON " + dbname + ".dbo.sources.id=" + dbname + ".dbo." + db + "._from";
|
||||
}
|
||||
subWhere = "";
|
||||
if (options.id) {
|
||||
subWhere += " " + dbname + ".dbo." + db + ".id=" + options.id;
|
||||
}
|
||||
if (options.ignoreNull) {
|
||||
//subWhere += (subWhere ? " AND" : "") + " val <> NULL";
|
||||
}
|
||||
subWhere += (subWhere ? " AND" : "") + " " + dbname + ".dbo." + db + ".ts >= " + options.end;
|
||||
if (subWhere) subQuery += " WHERE " + subWhere;
|
||||
subQuery += " ORDER BY " + dbname + ".dbo." + db + ".ts ASC";
|
||||
where += " UNION SELECT * FROM (" + subQuery + ") b";
|
||||
}
|
||||
|
||||
if (where) query += " WHERE " + where;
|
||||
|
||||
query += " ORDER BY ts";
|
||||
if (!options.start && options.count) {
|
||||
query += " DESC";
|
||||
} else {
|
||||
query += " ASC";
|
||||
}
|
||||
query += ";";
|
||||
return query;
|
||||
};
|
||||
146
lib/mysql.js
Normal file
146
lib/mysql.js
Normal file
@@ -0,0 +1,146 @@
|
||||
exports.init = function (dbname) {
|
||||
return [
|
||||
"CREATE DATABASE `" + dbname + "` DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;",
|
||||
"CREATE TABLE `" + dbname + "`.sources (id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, name TEXT);",
|
||||
"CREATE TABLE `" + dbname + "`.datapoints (id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, name TEXT, type INTEGER);",
|
||||
"CREATE TABLE `" + dbname + "`.ts_number (id INTEGER, ts BIGINT, val REAL, ack BOOLEAN, _from INTEGER, q INTEGER, PRIMARY KEY(id, ts));",
|
||||
"CREATE TABLE `" + dbname + "`.ts_string (id INTEGER, ts BIGINT, val TEXT, ack BOOLEAN, _from INTEGER, q INTEGER, PRIMARY KEY(id, ts));",
|
||||
"CREATE TABLE `" + dbname + "`.ts_bool (id INTEGER, ts BIGINT, val BOOLEAN, ack BOOLEAN, _from INTEGER, q INTEGER, PRIMARY KEY(id, ts));"
|
||||
];
|
||||
};
|
||||
|
||||
exports.destroy = function (dbname) {
|
||||
return [
|
||||
"DROP TABLE `" + dbname + "`.ts_number;",
|
||||
"DROP TABLE `" + dbname + "`.ts_string;",
|
||||
"DROP TABLE `" + dbname + "`.ts_bool;",
|
||||
"DROP TABLE `" + dbname + "`.sources;",
|
||||
"DROP TABLE `" + dbname + "`.datapoints;",
|
||||
"DROP DATABASE `" + dbname + "`;"
|
||||
];
|
||||
};
|
||||
|
||||
exports.getFirstTs = function (dbname, db) {
|
||||
return "SELECT id, MIN(ts) AS ts FROM `" + dbname + "`." + db + " GROUP BY id;";
|
||||
};
|
||||
|
||||
exports.insert = function (dbname, index, state, from, db) {
|
||||
if (state.val === null) state.val = 'NULL';
|
||||
else if (db === "ts_string") state.val = "'" + state.val.toString().replace(/'/g, '') + "'";
|
||||
return "INSERT INTO `" + dbname + "`." + db + " (id, ts, val, ack, _from, q) VALUES(" + index + ", " + state.ts + ", " + state.val + ", " + (state.ack ? 1 : 0) + ", " + (from || 0) + ", " + (state.q || 0) + ");";
|
||||
};
|
||||
|
||||
exports.retention = function (dbname, index, db, retention) {
|
||||
var d = new Date();
|
||||
d.setSeconds(-retention);
|
||||
var query = "DELETE FROM `" + dbname + "`." + db + " WHERE";
|
||||
query += " id=" + index;
|
||||
query += " AND ts < " + d.getTime();
|
||||
query += ";";
|
||||
return query;
|
||||
};
|
||||
|
||||
exports.getIdSelect = function (dbname, name) {
|
||||
if (!name) {
|
||||
return "SELECT id, type, name FROM `" + dbname + "`.datapoints;";
|
||||
} else {
|
||||
return "SELECT id, type, name FROM `" + dbname + "`.datapoints WHERE name='" + name + "';";
|
||||
}
|
||||
};
|
||||
|
||||
exports.getIdInsert = function (dbname, name, type) {
|
||||
return "INSERT INTO `" + dbname + "`.datapoints (name, type) VALUES('" + name + "', " + type + ");";
|
||||
};
|
||||
|
||||
exports.getIdUpdate = function (dbname, id, type) {
|
||||
return "UPDATE `" + dbname + "`.datapoints SET type = " + type + " WHERE id = " + id + ";";
|
||||
};
|
||||
|
||||
exports.getFromSelect = function (dbname, from) {
|
||||
return "SELECT id FROM `" + dbname + "`.sources WHERE name='" + from + "';";
|
||||
};
|
||||
|
||||
exports.getFromInsert = function (dbname, from) {
|
||||
return "INSERT INTO `" + dbname + "`.sources (name) VALUES('" + from + "');";
|
||||
};
|
||||
|
||||
exports.getHistory = function (dbname, db, options) {
|
||||
var query = "SELECT ts, val" +
|
||||
(!options.id ? (", " + db + ".id as id") : "") +
|
||||
(options.ack ? ", ack" : "") +
|
||||
(options.from ? (", `" + dbname + "`.sources.name as 'from'") : "") +
|
||||
(options.q ? ", q" : "") + " FROM `" + dbname + "`." + db;
|
||||
|
||||
if (options.from) {
|
||||
query += " INNER JOIN `" + dbname + "`.sources ON `" + dbname + "`.sources.id=`" + dbname + "`." + db + "._from";
|
||||
}
|
||||
|
||||
var where = "";
|
||||
|
||||
if (options.id) {
|
||||
where += " `" + dbname + "`." + db + ".id=" + options.id;
|
||||
}
|
||||
if (options.end) {
|
||||
where += (where ? " AND" : "") + " `" + dbname + "`." + db + ".ts < " + options.end;
|
||||
}
|
||||
if (options.start) {
|
||||
where += (where ? " AND" : "") + " `" + dbname + "`." + db + ".ts >= " + options.start;
|
||||
|
||||
var subQuery;
|
||||
var subWhere;
|
||||
subQuery = " SELECT ts, val" +
|
||||
(!options.id ? (", " + db + ".id as id") : "") +
|
||||
(options.ack ? ", ack" : "") +
|
||||
(options.from ? (", `" + dbname + "`.sources.name as 'from'") : "") +
|
||||
(options.q ? ", q" : "") + " FROM `" + dbname + "`." + db;
|
||||
if (options.from) {
|
||||
subQuery += " INNER JOIN `" + dbname + "`.sources ON `" + dbname + "`.sources.id=`" + dbname + "`." + db + "._from";
|
||||
}
|
||||
subWhere = "";
|
||||
if (options.id) {
|
||||
subWhere += " `" + dbname + "`." + db + ".id=" + options.id;
|
||||
}
|
||||
if (options.ignoreNull) {
|
||||
//subWhere += (subWhere ? " AND" : "") + " val <> NULL";
|
||||
}
|
||||
subWhere += (subWhere ? " AND" : "") + " `" + dbname + "`." + db + ".ts < " + options.start;
|
||||
if (subWhere) subQuery += " WHERE " + subWhere;
|
||||
subQuery += " ORDER BY `" + dbname + "`." + db + ".ts DESC LIMIT 1";
|
||||
where += " UNION (" + subQuery + ")";
|
||||
|
||||
//add next value after end
|
||||
subQuery = " SELECT ts, val" +
|
||||
(!options.id ? (", " + db + ".id as id") : "") +
|
||||
(options.ack ? ", ack" : "") +
|
||||
(options.from ? (", `" + dbname + "`.sources.name as 'from'") : "") +
|
||||
(options.q ? ", q" : "") + " FROM `" + dbname + "`." + db;
|
||||
if (options.from) {
|
||||
subQuery += " INNER JOIN `" + dbname + "`.sources ON `" + dbname + "`.sources.id=`" + dbname + "`." + db + "._from";
|
||||
}
|
||||
subWhere = "";
|
||||
if (options.id) {
|
||||
subWhere += " `" + dbname + "`." + db + ".id=" + options.id;
|
||||
}
|
||||
if (options.ignoreNull) {
|
||||
//subWhere += (subWhere ? " AND" : "") + " val <> NULL";
|
||||
}
|
||||
subWhere += (subWhere ? " AND" : "") + " `" + dbname + "`." + db + ".ts >= " + options.end;
|
||||
if (subWhere) subQuery += " WHERE " + subWhere;
|
||||
subQuery += " ORDER BY `" + dbname + "`." + db + ".ts ASC LIMIT 1";
|
||||
where += " UNION (" + subQuery + ")";
|
||||
|
||||
}
|
||||
|
||||
if (where) query += " WHERE " + where;
|
||||
|
||||
query += " ORDER BY ts";
|
||||
|
||||
if (!options.start && options.count) {
|
||||
query += " DESC LIMIT " + options.count;
|
||||
} else {
|
||||
query += " ASC";
|
||||
}
|
||||
|
||||
query += ";";
|
||||
return query;
|
||||
};
|
||||
158
lib/postgresql-client.js
Normal file
158
lib/postgresql-client.js
Normal file
@@ -0,0 +1,158 @@
|
||||
// Generated by CoffeeScript 1.10.0
|
||||
(function() {
|
||||
var ConnectionFactory, PostgreSQLClient, PostgreSQLClient2, PostgreSQLClientPool, PostgreSQLClientPool2, PostgreSQLConnectionFactory, PostgreSQLConnectionFactory2, SQLClient, SQLClientPool, pg,
|
||||
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
|
||||
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||
hasProp = {}.hasOwnProperty,
|
||||
slice = [].slice;
|
||||
|
||||
SQLClient = require('sql-client/lib/sql-client').SQLClient;
|
||||
|
||||
SQLClientPool = require('sql-client/lib/sql-client-pool').SQLClientPool;
|
||||
|
||||
ConnectionFactory = require('sql-client/lib/connection-factory').ConnectionFactory;
|
||||
|
||||
pg = require('pg');
|
||||
try {
|
||||
if ((pg != null ? pg["native"] : void 0) != null) {
|
||||
pg = pg["native"];
|
||||
}
|
||||
} catch(err) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
PostgreSQLConnectionFactory = (function(superClass) {
|
||||
extend(PostgreSQLConnectionFactory, superClass);
|
||||
|
||||
function PostgreSQLConnectionFactory() {
|
||||
this.pre_process_sql = bind(this.pre_process_sql, this);
|
||||
this.open_connection = bind(this.open_connection, this);
|
||||
return PostgreSQLConnectionFactory.__super__.constructor.apply(this, arguments);
|
||||
}
|
||||
|
||||
PostgreSQLConnectionFactory.prototype.open_connection = function(connect_string, callback) {
|
||||
var connection;
|
||||
connection = new pg.Client(connect_string);
|
||||
return connection.connect((function(_this) {
|
||||
return function(err) {
|
||||
return callback(err, connection);
|
||||
};
|
||||
})(this));
|
||||
};
|
||||
|
||||
PostgreSQLConnectionFactory.prototype.pre_process_sql = function(sql, bindvars, callback) {
|
||||
var index;
|
||||
if ((sql != null) && (bindvars != null)) {
|
||||
index = 1;
|
||||
sql = sql.replace(/\?/g, (function() {
|
||||
return '$' + index++;
|
||||
}));
|
||||
}
|
||||
return callback(null, sql, bindvars);
|
||||
};
|
||||
|
||||
return PostgreSQLConnectionFactory;
|
||||
|
||||
})(ConnectionFactory);
|
||||
|
||||
PostgreSQLClient = (function(superClass) {
|
||||
extend(PostgreSQLClient, superClass);
|
||||
|
||||
function PostgreSQLClient() {
|
||||
var options;
|
||||
options = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||
PostgreSQLClient.__super__.constructor.apply(this, slice.call(options).concat([new PostgreSQLConnectionFactory()]));
|
||||
}
|
||||
|
||||
return PostgreSQLClient;
|
||||
|
||||
})(SQLClient);
|
||||
|
||||
PostgreSQLClientPool = (function(superClass) {
|
||||
extend(PostgreSQLClientPool, superClass);
|
||||
|
||||
function PostgreSQLClientPool() {
|
||||
var options;
|
||||
options = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||
PostgreSQLClientPool.__super__.constructor.apply(this, slice.call(options).concat([new PostgreSQLConnectionFactory()]));
|
||||
}
|
||||
|
||||
return PostgreSQLClientPool;
|
||||
|
||||
})(SQLClientPool);
|
||||
|
||||
exports.PostgreSQLConnectionFactory = PostgreSQLConnectionFactory;
|
||||
|
||||
exports.PostgreSQLClient = PostgreSQLClient;
|
||||
|
||||
exports.PostgreSQLClientPool = PostgreSQLClientPool;
|
||||
|
||||
PostgreSQLConnectionFactory2 = (function(superClass) {
|
||||
extend(PostgreSQLConnectionFactory2, superClass);
|
||||
|
||||
function PostgreSQLConnectionFactory2() {
|
||||
this.close_connection = bind(this.close_connection, this);
|
||||
this.open_connection = bind(this.open_connection, this);
|
||||
return PostgreSQLConnectionFactory2.__super__.constructor.apply(this, arguments);
|
||||
}
|
||||
|
||||
PostgreSQLConnectionFactory2.prototype.open_connection = function(connect_string, callback) {
|
||||
return pg.connect(connect_string, (function(_this) {
|
||||
return function(err, client, done_fn) {
|
||||
var connection;
|
||||
connection = client;
|
||||
if (connection != null) {
|
||||
connection._sqlclient_done = done_fn;
|
||||
}
|
||||
return callback(err, connection);
|
||||
};
|
||||
})(this));
|
||||
};
|
||||
|
||||
PostgreSQLConnectionFactory2.prototype.close_connection = function(connection, callback) {
|
||||
if ((connection != null ? connection._sqlclient_done : void 0) != null) {
|
||||
connection._sqlclient_done();
|
||||
return typeof callback === "function" ? callback(null) : void 0;
|
||||
} else {
|
||||
return PostgreSQLConnectionFactory2.__super__.close_connection.apply(this, arguments).close_connection(connection, callback);
|
||||
}
|
||||
};
|
||||
|
||||
return PostgreSQLConnectionFactory2;
|
||||
|
||||
})(PostgreSQLConnectionFactory);
|
||||
|
||||
PostgreSQLClient2 = (function(superClass) {
|
||||
extend(PostgreSQLClient2, superClass);
|
||||
|
||||
function PostgreSQLClient2() {
|
||||
var options;
|
||||
options = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||
PostgreSQLClient2.__super__.constructor.apply(this, slice.call(options).concat([new PostgreSQLConnectionFactory2()]));
|
||||
}
|
||||
|
||||
return PostgreSQLClient2;
|
||||
|
||||
})(SQLClient);
|
||||
|
||||
PostgreSQLClientPool2 = (function(superClass) {
|
||||
extend(PostgreSQLClientPool2, superClass);
|
||||
|
||||
function PostgreSQLClientPool2() {
|
||||
var options;
|
||||
options = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||
PostgreSQLClientPool2.__super__.constructor.apply(this, slice.call(options).concat([new PostgreSQLConnectionFactory2()]));
|
||||
}
|
||||
|
||||
return PostgreSQLClientPool2;
|
||||
|
||||
})(SQLClientPool);
|
||||
|
||||
exports.PostgreSQLConnectionFactory2 = PostgreSQLConnectionFactory2;
|
||||
|
||||
exports.PostgreSQLClient2 = PostgreSQLClient2;
|
||||
|
||||
exports.PostgreSQLClientPool2 = PostgreSQLClientPool2;
|
||||
|
||||
}).call(this);
|
||||
145
lib/postgresql.js
Normal file
145
lib/postgresql.js
Normal file
@@ -0,0 +1,145 @@
|
||||
exports.init = function (dbname) {
|
||||
return [
|
||||
"CREATE TABLE sources (id SERIAL NOT NULL PRIMARY KEY, name TEXT);",
|
||||
"CREATE TABLE datapoints (id SERIAL NOT NULL PRIMARY KEY, name TEXT, type INTEGER);",
|
||||
"CREATE TABLE ts_number (id INTEGER NOT NULL, ts BIGINT, val REAL, ack BOOLEAN, _from INTEGER, q INTEGER, PRIMARY KEY(id, ts));",
|
||||
"CREATE TABLE ts_string (id INTEGER NOT NULL, ts BIGINT, val TEXT, ack BOOLEAN, _from INTEGER, q INTEGER, PRIMARY KEY(id, ts));",
|
||||
"CREATE TABLE ts_bool (id INTEGER NOT NULL, ts BIGINT, val BOOLEAN, ack BOOLEAN, _from INTEGER, q INTEGER, PRIMARY KEY(id, ts));"
|
||||
];
|
||||
};
|
||||
|
||||
exports.destroy = function (dbname) {
|
||||
return [
|
||||
"DROP TABLE ts_number;",
|
||||
"DROP TABLE ts_string;",
|
||||
"DROP TABLE ts_bool;",
|
||||
"DROP TABLE sources;",
|
||||
"DROP TABLE datapoints;"
|
||||
];
|
||||
};
|
||||
|
||||
exports.getFirstTs = function (dbname, db) {
|
||||
return "SELECT id, MIN(ts) AS ts FROM " + db + " GROUP BY id;";
|
||||
};
|
||||
|
||||
exports.insert = function (dbname, index, state, from, db) {
|
||||
if (state.val === null) state.val = 'NULL';
|
||||
else if (db === "ts_string") state.val = "'" + state.val.toString().replace(/'/g, '') + "'";
|
||||
return "INSERT INTO " + db + " (id, ts, val, ack, _from, q) VALUES(" + index + ", " + state.ts + ", " + state.val + ", " + (!!state.ack) + ", " + (from || 0) + ", " + (state.q || 0) + ");";
|
||||
};
|
||||
|
||||
exports.retention = function (dbname, index, db, retention) {
|
||||
var d = new Date();
|
||||
d.setSeconds(-retention);
|
||||
var query = "DELETE FROM " + db + " WHERE";
|
||||
query += " id=" + index;
|
||||
query += " AND ts < " + d.getTime();
|
||||
query += ";";
|
||||
|
||||
return query;
|
||||
};
|
||||
|
||||
exports.getIdSelect = function (dbname, name) {
|
||||
if (!name) {
|
||||
return "SELECT id, type, name FROM datapoints;";
|
||||
} else {
|
||||
return "SELECT id, type, name FROM datapoints WHERE name='" + name + "';";
|
||||
}
|
||||
};
|
||||
|
||||
exports.getIdInsert = function (dbname, name, type) {
|
||||
return "INSERT INTO datapoints (name, type) VALUES('" + name + "', " + type + ");";
|
||||
};
|
||||
|
||||
exports.getIdUpdate = function (dbname, id, type) {
|
||||
return "UPDATE datapoints SET type = " + type + " WHERE id = " + id + ";";
|
||||
};
|
||||
|
||||
exports.getFromSelect = function (dbname, from) {
|
||||
return "SELECT id FROM sources WHERE name='" + from + "';";
|
||||
};
|
||||
|
||||
exports.getFromInsert = function (dbname, from) {
|
||||
return "INSERT INTO sources (name) VALUES('" + from + "');";
|
||||
};
|
||||
exports.getHistory = function (dbname, db, options) {
|
||||
var query = "SELECT ts, val" +
|
||||
(!options.id ? (", " + db + ".id as id") : "") +
|
||||
(options.ack ? ", ack" : "") +
|
||||
(options.from ? (", sources.name as from") : "") +
|
||||
(options.q ? ", q" : "") + " FROM " + db;
|
||||
|
||||
if (options.from) {
|
||||
query += " INNER JOIN sources ON sources.id=" + db + "._from";
|
||||
}
|
||||
|
||||
var where = "";
|
||||
|
||||
if (options.id) {
|
||||
where += " " + db + ".id=" + options.id;
|
||||
}
|
||||
if (options.end) {
|
||||
where += (where ? " AND" : "") + " " + db + ".ts < " + options.end;
|
||||
}
|
||||
if (options.start) {
|
||||
where += (where ? " AND" : "") + " " + db + ".ts >= " + options.start;
|
||||
|
||||
//add last value before start
|
||||
var subQuery;
|
||||
var subWhere;
|
||||
subQuery = " SELECT ts, val" +
|
||||
(!options.id ? (", " + db + ".id as id") : "") +
|
||||
(options.ack ? ", ack" : "") +
|
||||
(options.from ? (", sources.name as from") : "") +
|
||||
(options.q ? ", q" : "") + " FROM " + db;
|
||||
if (options.from) {
|
||||
subQuery += " INNER JOIN sources ON sources.id=" + db + "._from";
|
||||
}
|
||||
subWhere = "";
|
||||
if (options.id) {
|
||||
subWhere += " " + db + ".id=" + options.id;
|
||||
}
|
||||
if (options.ignoreNull) {
|
||||
//subWhere += (subWhere ? " AND" : "") + " val <> NULL";
|
||||
}
|
||||
subWhere += (subWhere ? " AND" : "") + " " + db + ".ts < " + options.start;
|
||||
if (subWhere) subQuery += " WHERE " + subWhere;
|
||||
subQuery += " ORDER BY " + db + ".ts DESC LIMIT 1";
|
||||
where += " UNION (" + subQuery + ")";
|
||||
|
||||
//add next value after end
|
||||
subQuery = " SELECT ts, val" +
|
||||
(!options.id ? (", " + db + ".id as id") : "") +
|
||||
(options.ack ? ", ack" : "") +
|
||||
(options.from ? (", sources.name as from") : "") +
|
||||
(options.q ? ", q" : "") + " FROM " + db;
|
||||
if (options.from) {
|
||||
subQuery += " INNER JOIN sources ON sources.id=" + db + "._from";
|
||||
}
|
||||
subWhere = "";
|
||||
if (options.id) {
|
||||
subWhere += " " + db + ".id=" + options.id;
|
||||
}
|
||||
if (options.ignoreNull) {
|
||||
//subWhere += (subWhere ? " AND" : "") + " val <> NULL";
|
||||
}
|
||||
subWhere += (subWhere ? " AND" : "") + " " + db + ".ts >= " + options.end;
|
||||
if (subWhere) subQuery += " WHERE " + subWhere;
|
||||
subQuery += " ORDER BY " + db + ".ts ASC LIMIT 1";
|
||||
where += " UNION (" + subQuery + ")";
|
||||
}
|
||||
|
||||
if (where) query += " WHERE " + where;
|
||||
|
||||
|
||||
query += " ORDER BY ts";
|
||||
|
||||
if (!options.start && options.count) {
|
||||
query += " DESC LIMIT " + options.count;
|
||||
} else {
|
||||
query += " ASC";
|
||||
}
|
||||
|
||||
query += ";";
|
||||
return query;
|
||||
};
|
||||
149
lib/sqlite.js
Normal file
149
lib/sqlite.js
Normal file
@@ -0,0 +1,149 @@
|
||||
exports.init = function (dbname) {
|
||||
return [
|
||||
"CREATE TABLE sources (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name TEXT);",
|
||||
"CREATE TABLE datapoints (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name TEXT, type INTEGER);",
|
||||
"CREATE TABLE ts_number (id INTEGER, ts INTEGER, val REAL, ack BOOLEAN, _from INTEGER, q INTEGER, PRIMARY KEY(id, ts));",
|
||||
"CREATE TABLE ts_string (id INTEGER, ts INTEGER, val TEXT, ack BOOLEAN, _from INTEGER, q INTEGER, PRIMARY KEY(id, ts));",
|
||||
"CREATE TABLE ts_bool (id INTEGER, ts INTEGER, val BOOLEAN, ack BOOLEAN, _from INTEGER, q INTEGER, PRIMARY KEY(id, ts));"
|
||||
];
|
||||
};
|
||||
|
||||
exports.destroy = function (dbname) {
|
||||
return [
|
||||
"DROP TABLE ts_number;",
|
||||
"DROP TABLE ts_string;",
|
||||
"DROP TABLE ts_bool;",
|
||||
"DROP TABLE sources;",
|
||||
"DROP TABLE datapoints;"
|
||||
];
|
||||
};
|
||||
|
||||
exports.getFirstTs = function (dbname, db) {
|
||||
return "SELECT id, MIN(ts) AS ts FROM " + db + " GROUP BY id;";
|
||||
};
|
||||
|
||||
exports.insert = function (dbname, index, state, from, db) {
|
||||
if (state.val === null) state.val = 'NULL';
|
||||
else if (db === "ts_bool") state.val = state.val ? 1 : 0;
|
||||
else if (db === "ts_string") state.val = "'" + state.val.toString().replace(/'/g, '') + "'";
|
||||
return "INSERT INTO " + db + " (id, ts, val, ack, _from, q) VALUES(" + index + ", " + state.ts + ", " + state.val + ", " + (state.ack ? 1 : 0) + ", " + (from || 0) + ", " + (state.q || 0) + ");";
|
||||
};
|
||||
|
||||
exports.retention = function (dbname, index, db, retention) {
|
||||
var d = new Date();
|
||||
d.setSeconds(-retention);
|
||||
var query = "DELETE FROM " + db + " WHERE";
|
||||
query += " id=" + index;
|
||||
query += " AND ts < " + d.getTime();
|
||||
query += ";";
|
||||
return query;
|
||||
};
|
||||
|
||||
exports.getIdSelect = function (dbname, name) {
|
||||
if (!name) {
|
||||
return "SELECT id, type, name FROM datapoints;";
|
||||
} else {
|
||||
return "SELECT id, type, name FROM datapoints WHERE name='" + name + "';";
|
||||
}
|
||||
};
|
||||
|
||||
exports.getIdInsert = function (dbname, name, type) {
|
||||
return "INSERT INTO datapoints (name, type) VALUES('" + name + "', " + type + ");";
|
||||
};
|
||||
|
||||
exports.getIdUpdate = function (dbname, id, type) {
|
||||
return "UPDATE datapoints SET type = " + type + " WHERE id = " + id + ";";
|
||||
};
|
||||
|
||||
exports.getFromSelect = function (dbname, from) {
|
||||
if (!from) {
|
||||
return "SELECT id, name FROM sources;";
|
||||
} else {
|
||||
return "SELECT id FROM sources WHERE name='" + from + "';";
|
||||
}
|
||||
};
|
||||
|
||||
exports.getFromInsert = function (dbname, from) {
|
||||
return "INSERT INTO sources (name) VALUES('" + from + "');";
|
||||
};
|
||||
|
||||
exports.getHistory = function (dbname, db, options) {
|
||||
var query = "SELECT ts, val" +
|
||||
(!options.id ? (", " + db + ".id as id") : "") +
|
||||
(options.ack ? ", ack" : "") +
|
||||
(options.from ? (", sources.name as 'from'") : "") +
|
||||
(options.q ? ", q" : "") + " FROM " + db;
|
||||
|
||||
if (options.from) {
|
||||
query += " INNER JOIN sources ON sources.id=" + db + "._from";
|
||||
}
|
||||
|
||||
var where = "";
|
||||
|
||||
if (options.id) {
|
||||
where += " " + db + ".id=" + options.id;
|
||||
}
|
||||
if (options.end) {
|
||||
where += (where ? " AND" : "") + " " + db + ".ts < " + options.end;
|
||||
}
|
||||
if (options.start) {
|
||||
where += (where ? " AND" : "") + " " + db + ".ts >= " + options.start;
|
||||
|
||||
//add last value before start
|
||||
var subQuery;
|
||||
var subWhere;
|
||||
subQuery = " SELECT ts, val" +
|
||||
(!options.id ? (", " + db + ".id as id") : "") +
|
||||
(options.ack ? ", ack" : "") +
|
||||
(options.from ? (", sources.name as 'from'") : "") +
|
||||
(options.q ? ", q" : "") + " FROM " + db;
|
||||
if (options.from) {
|
||||
subQuery += " INNER JOIN sources ON sources.id=" + db + "._from";
|
||||
}
|
||||
subWhere = "";
|
||||
if (options.id) {
|
||||
subWhere += " " + db + ".id=" + options.id;
|
||||
}
|
||||
if (options.ignoreNull) {
|
||||
//subWhere += (subWhere ? " AND" : "") + " val <> NULL";
|
||||
}
|
||||
subWhere += (subWhere ? " AND" : "") + " " + db + ".ts < " + options.start;
|
||||
if (subWhere) subQuery += " WHERE " + subWhere;
|
||||
subQuery += " ORDER BY " + db + ".ts DESC LIMIT 1";
|
||||
where += " UNION SELECT * from (" + subQuery + ")";
|
||||
|
||||
//add next value after end
|
||||
subQuery = " SELECT ts, val" +
|
||||
(!options.id ? (", " + db + ".id as id") : "") +
|
||||
(options.ack ? ", ack" : "") +
|
||||
(options.from ? (", sources.name as 'from'") : "") +
|
||||
(options.q ? ", q" : "") + " FROM " + db;
|
||||
if (options.from) {
|
||||
subQuery += " INNER JOIN sources ON sources.id=" + db + "._from";
|
||||
}
|
||||
subWhere = "";
|
||||
if (options.id) {
|
||||
subWhere += " " + db + ".id=" + options.id;
|
||||
}
|
||||
if (options.ignoreNull) {
|
||||
//subWhere += (subWhere ? " AND" : "") + " val <> NULL";
|
||||
}
|
||||
subWhere += (subWhere ? " AND" : "") + " " + db + ".ts >= " + options.end;
|
||||
if (subWhere) subQuery += " WHERE " + subWhere;
|
||||
subQuery += " ORDER BY " + db + ".ts ASC LIMIT 1";
|
||||
where += " UNION SELECT * from (" + subQuery + ") ";
|
||||
}
|
||||
|
||||
if (where) query += " WHERE " + where;
|
||||
|
||||
query += " ORDER BY ts";
|
||||
|
||||
if (!options.start && options.count) {
|
||||
query += " DESC LIMIT " + options.count;
|
||||
} else {
|
||||
query += " ASC";
|
||||
}
|
||||
|
||||
query += ";";
|
||||
return query;
|
||||
};
|
||||
83
lib/utils.js
Normal file
83
lib/utils.js
Normal file
@@ -0,0 +1,83 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
let controllerDir;
|
||||
let appName;
|
||||
|
||||
/**
|
||||
* returns application name
|
||||
*
|
||||
* The name of the application can be different and this function finds it out.
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
function getAppName() {
|
||||
const parts = __dirname.replace(/\\/g, '/').split('/');
|
||||
return parts[parts.length - 2].split('.')[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* looks for js-controller home folder
|
||||
*
|
||||
* @param {boolean} isInstall
|
||||
* @returns {string}
|
||||
*/
|
||||
function getControllerDir(isInstall) {
|
||||
// Find the js-controller location
|
||||
const possibilities = [
|
||||
'yunkong2.js-controller',
|
||||
'yunkong2.js-controller',
|
||||
];
|
||||
/** @type {string} */
|
||||
let controllerPath;
|
||||
for (const pkg of possibilities) {
|
||||
try {
|
||||
const possiblePath = require.resolve(pkg);
|
||||
if (fs.existsSync(possiblePath)) {
|
||||
controllerPath = possiblePath;
|
||||
break;
|
||||
}
|
||||
} catch (e) { /* not found */ }
|
||||
}
|
||||
if (controllerPath == null) {
|
||||
if (!isInstall) {
|
||||
console.log('Cannot find js-controller');
|
||||
process.exit(10);
|
||||
} else {
|
||||
process.exit();
|
||||
}
|
||||
}
|
||||
// we found the controller
|
||||
return path.dirname(controllerPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* reads controller base settings
|
||||
*
|
||||
* @alias getConfig
|
||||
* @returns {object}
|
||||
*/
|
||||
function getConfig() {
|
||||
let configPath;
|
||||
if (fs.existsSync(
|
||||
configPath = path.join(controllerDir, 'conf', appName + '.json')
|
||||
)) {
|
||||
return JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
||||
} else if (fs.existsSync(
|
||||
configPath = path.join(controllerDir, 'conf', + appName.toLowerCase() + '.json')
|
||||
)) {
|
||||
return JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
||||
} else {
|
||||
throw new Error('Cannot find ' + controllerDir + '/conf/' + appName + '.json');
|
||||
}
|
||||
}
|
||||
appName = getAppName();
|
||||
controllerDir = getControllerDir(typeof process !== 'undefined' && process.argv && process.argv.indexOf('--install') !== -1);
|
||||
const adapter = require(path.join(controllerDir, 'lib/adapter.js'));
|
||||
|
||||
exports.controllerDir = controllerDir;
|
||||
exports.getConfig = getConfig;
|
||||
exports.Adapter = adapter;
|
||||
exports.appName = appName;
|
||||
48
package.json
Normal file
48
package.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"name": "yunkong2.sql",
|
||||
"description": "Log state sql in a two-stages process (first to Redis, then to CouchDB)",
|
||||
"version": "1.9.2",
|
||||
"author": "bluefox <dogafox@gmail.com>",
|
||||
"contributors": [
|
||||
"bluefox <dogafox@gmail.com>",
|
||||
"Apollon77"
|
||||
],
|
||||
"homepage": "https://git.spacen.net/yunkong2/yunkong2.sql",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://git.spacen.net/yunkong2/yunkong2.sql"
|
||||
},
|
||||
"licenses": [
|
||||
{
|
||||
"type": "MIT",
|
||||
"url": "https://git.spacen.net/yunkong2/yunkong2.sql/blob/master/LICENSE"
|
||||
}
|
||||
],
|
||||
"keywords": [
|
||||
"yunkong2",
|
||||
"log data",
|
||||
"home automation"
|
||||
],
|
||||
"optionalDependencies": {
|
||||
"mysql": "^2.15.0",
|
||||
"pg": "^6.1.5",
|
||||
"sqlite3": "^4.0.1",
|
||||
"mssql": "^3.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"sql-client": "0.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"gulp": "^3.9.1",
|
||||
"mocha": "^4.1.0",
|
||||
"chai": "^4.1.2"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://git.spacen.net/yunkong2/yunkong2.sql/issues"
|
||||
},
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"test": "node node_modules/mocha/bin/mocha --exit"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
||||
17
tasks/jscs.js
Normal file
17
tasks/jscs.js
Normal file
@@ -0,0 +1,17 @@
|
||||
var srcDir = __dirname + "/../";
|
||||
|
||||
module.exports = {
|
||||
all: {
|
||||
src: [
|
||||
srcDir + "*.js",
|
||||
srcDir + "lib/*.js",
|
||||
srcDir + "adapter/example/*.js",
|
||||
srcDir + "tasks/**/*.js",
|
||||
srcDir + "www/**/*.js",
|
||||
'!' + srcDir + "www/lib/**/*.js",
|
||||
'!' + srcDir + 'node_modules/**/*.js',
|
||||
'!' + srcDir + 'adapter/*/node_modules/**/*.js'
|
||||
],
|
||||
options: require('./jscsRules.js')
|
||||
}
|
||||
};
|
||||
36
tasks/jscsRules.js
Normal file
36
tasks/jscsRules.js
Normal file
@@ -0,0 +1,36 @@
|
||||
module.exports = {
|
||||
force: true,
|
||||
"requireCurlyBraces": ["else", "for", "while", "do", "try", "catch"], /*"if",*/
|
||||
"requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch", "return", "try", "catch"],
|
||||
"requireSpaceBeforeBlockStatements": true,
|
||||
"requireParenthesesAroundIIFE": true,
|
||||
"disallowSpacesInFunctionDeclaration": {"beforeOpeningRoundBrace": true},
|
||||
"disallowSpacesInNamedFunctionExpression": {"beforeOpeningRoundBrace": true},
|
||||
"requireSpacesInFunctionExpression": {"beforeOpeningCurlyBrace": true},
|
||||
"requireSpacesInAnonymousFunctionExpression": {"beforeOpeningRoundBrace": true, "beforeOpeningCurlyBrace": true},
|
||||
"requireSpacesInNamedFunctionExpression": {"beforeOpeningCurlyBrace": true},
|
||||
"requireSpacesInFunctionDeclaration": {"beforeOpeningCurlyBrace": true},
|
||||
"disallowMultipleVarDecl": true,
|
||||
"requireBlocksOnNewline": true,
|
||||
"disallowEmptyBlocks": true,
|
||||
"disallowSpacesInsideObjectBrackets": true,
|
||||
"disallowSpacesInsideArrayBrackets": true,
|
||||
"disallowSpaceAfterObjectKeys": true,
|
||||
"disallowSpacesInsideParentheses": true,
|
||||
"requireCommaBeforeLineBreak": true,
|
||||
//"requireAlignedObjectValues": "all",
|
||||
"requireOperatorBeforeLineBreak": ["?", "+", "-", "/", "*", "=", "==", "===", "!=", "!==", ">", ">=", "<", "<="],
|
||||
// "disallowLeftStickedOperators": ["?", "+", "/", "*", "=", "==", "===", "!=", "!==", ">", ">=", "<", "<="],
|
||||
// "requireRightStickedOperators": ["!"],
|
||||
// "requireSpaceAfterBinaryOperators": ["?", "+", "/", "*", ":", "=", "==", "===", "!=", "!==", ">", ">=", "<", "<="],
|
||||
//"disallowSpaceAfterBinaryOperators": [","],
|
||||
"disallowSpaceAfterPrefixUnaryOperators": ["++", "--", "+", "-", "~", "!"],
|
||||
"disallowSpaceBeforePostfixUnaryOperators": ["++", "--"],
|
||||
"requireSpaceBeforeBinaryOperators": ["+", "-", "/", "*", "=", "==", "===", "!=", "!=="],
|
||||
"requireSpaceAfterBinaryOperators": ["?", ">", ",", ">=", "<=", "<", "+", "-", "/", "*", "=", "==", "===", "!=", "!=="],
|
||||
//"validateIndentation": 4,
|
||||
//"validateQuoteMarks": { "mark": "\"", "escape": true },
|
||||
"disallowMixedSpacesAndTabs": true,
|
||||
"disallowKeywordsOnNewLine": ["else", "catch"]
|
||||
|
||||
};
|
||||
17
tasks/jshint.js
Normal file
17
tasks/jshint.js
Normal file
@@ -0,0 +1,17 @@
|
||||
var srcDir = __dirname + "/../";
|
||||
|
||||
module.exports = {
|
||||
options: {
|
||||
force: true
|
||||
},
|
||||
all: [
|
||||
srcDir + "*.js",
|
||||
srcDir + "lib/*.js",
|
||||
srcDir + "adapter/example/*.js",
|
||||
srcDir + "tasks/**/*.js",
|
||||
srcDir + "www/**/*.js",
|
||||
'!' + srcDir + "www/lib/**/*.js",
|
||||
'!' + srcDir + 'node_modules/**/*.js',
|
||||
'!' + srcDir + 'adapter/*/node_modules/**/*.js'
|
||||
]
|
||||
};
|
||||
728
test/lib/setup.js
Normal file
728
test/lib/setup.js
Normal file
@@ -0,0 +1,728 @@
|
||||
/* jshint -W097 */// jshint strict:false
|
||||
/*jslint node: true */
|
||||
// check if tmp directory exists
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var child_process = require('child_process');
|
||||
var rootDir = path.normalize(__dirname + '/../../');
|
||||
var pkg = require(rootDir + 'package.json');
|
||||
var debug = typeof v8debug === 'object';
|
||||
pkg.main = pkg.main || 'main.js';
|
||||
|
||||
var adapterName = path.normalize(rootDir).replace(/\\/g, '/').split('/');
|
||||
adapterName = adapterName[adapterName.length - 2];
|
||||
var adapterStarted = false;
|
||||
|
||||
function getAppName() {
|
||||
var parts = __dirname.replace(/\\/g, '/').split('/');
|
||||
return parts[parts.length - 3].split('.')[0];
|
||||
}
|
||||
|
||||
var appName = getAppName().toLowerCase();
|
||||
|
||||
var objects;
|
||||
var states;
|
||||
|
||||
var pid = null;
|
||||
|
||||
function copyFileSync(source, target) {
|
||||
|
||||
var targetFile = target;
|
||||
|
||||
//if target is a directory a new file with the same name will be created
|
||||
if (fs.existsSync(target)) {
|
||||
if ( fs.lstatSync( target ).isDirectory() ) {
|
||||
targetFile = path.join(target, path.basename(source));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
fs.writeFileSync(targetFile, fs.readFileSync(source));
|
||||
}
|
||||
catch (err) {
|
||||
console.log("file copy error: " +source +" -> " + targetFile + " (error ignored)");
|
||||
}
|
||||
}
|
||||
|
||||
function copyFolderRecursiveSync(source, target, ignore) {
|
||||
var files = [];
|
||||
|
||||
var base = path.basename(source);
|
||||
if (base === adapterName) {
|
||||
base = pkg.name;
|
||||
}
|
||||
//check if folder needs to be created or integrated
|
||||
var targetFolder = path.join(target, base);
|
||||
if (!fs.existsSync(targetFolder)) {
|
||||
fs.mkdirSync(targetFolder);
|
||||
}
|
||||
|
||||
//copy
|
||||
if (fs.lstatSync(source).isDirectory()) {
|
||||
files = fs.readdirSync(source);
|
||||
files.forEach(function (file) {
|
||||
if (ignore && ignore.indexOf(file) !== -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
var curSource = path.join(source, file);
|
||||
var curTarget = path.join(targetFolder, file);
|
||||
if (fs.lstatSync(curSource).isDirectory()) {
|
||||
// ignore grunt files
|
||||
if (file.indexOf('grunt') !== -1) return;
|
||||
if (file === 'chai') return;
|
||||
if (file === 'mocha') return;
|
||||
copyFolderRecursiveSync(curSource, targetFolder, ignore);
|
||||
} else {
|
||||
copyFileSync(curSource, curTarget);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!fs.existsSync(rootDir + 'tmp')) {
|
||||
fs.mkdirSync(rootDir + 'tmp');
|
||||
}
|
||||
|
||||
function storeOriginalFiles() {
|
||||
console.log('Store original files...');
|
||||
var dataDir = rootDir + 'tmp/' + appName + '-data/';
|
||||
|
||||
var f = fs.readFileSync(dataDir + 'objects.json');
|
||||
var objects = JSON.parse(f.toString());
|
||||
if (objects['system.adapter.admin.0'] && objects['system.adapter.admin.0'].common) {
|
||||
objects['system.adapter.admin.0'].common.enabled = false;
|
||||
}
|
||||
if (objects['system.adapter.admin.1'] && objects['system.adapter.admin.1'].common) {
|
||||
objects['system.adapter.admin.1'].common.enabled = false;
|
||||
}
|
||||
|
||||
fs.writeFileSync(dataDir + 'objects.json.original', JSON.stringify(objects));
|
||||
try {
|
||||
f = fs.readFileSync(dataDir + 'states.json');
|
||||
fs.writeFileSync(dataDir + 'states.json.original', f);
|
||||
}
|
||||
catch (err) {
|
||||
console.log('no states.json found - ignore');
|
||||
}
|
||||
}
|
||||
|
||||
function restoreOriginalFiles() {
|
||||
console.log('restoreOriginalFiles...');
|
||||
var dataDir = rootDir + 'tmp/' + appName + '-data/';
|
||||
|
||||
var f = fs.readFileSync(dataDir + 'objects.json.original');
|
||||
fs.writeFileSync(dataDir + 'objects.json', f);
|
||||
try {
|
||||
f = fs.readFileSync(dataDir + 'states.json.original');
|
||||
fs.writeFileSync(dataDir + 'states.json', f);
|
||||
}
|
||||
catch (err) {
|
||||
console.log('no states.json.original found - ignore');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function checkIsAdapterInstalled(cb, counter, customName) {
|
||||
customName = customName || pkg.name.split('.').pop();
|
||||
counter = counter || 0;
|
||||
var dataDir = rootDir + 'tmp/' + appName + '-data/';
|
||||
console.log('checkIsAdapterInstalled...');
|
||||
|
||||
try {
|
||||
var f = fs.readFileSync(dataDir + 'objects.json');
|
||||
var objects = JSON.parse(f.toString());
|
||||
if (objects['system.adapter.' + customName + '.0']) {
|
||||
console.log('checkIsAdapterInstalled: ready!');
|
||||
setTimeout(function () {
|
||||
if (cb) cb();
|
||||
}, 100);
|
||||
return;
|
||||
} else {
|
||||
console.warn('checkIsAdapterInstalled: still not ready');
|
||||
}
|
||||
} catch (err) {
|
||||
|
||||
}
|
||||
|
||||
if (counter > 20) {
|
||||
console.error('checkIsAdapterInstalled: Cannot install!');
|
||||
if (cb) cb('Cannot install');
|
||||
} else {
|
||||
console.log('checkIsAdapterInstalled: wait...');
|
||||
setTimeout(function() {
|
||||
checkIsAdapterInstalled(cb, counter + 1);
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
function checkIsControllerInstalled(cb, counter) {
|
||||
counter = counter || 0;
|
||||
var dataDir = rootDir + 'tmp/' + appName + '-data/';
|
||||
|
||||
console.log('checkIsControllerInstalled...');
|
||||
try {
|
||||
var f = fs.readFileSync(dataDir + 'objects.json');
|
||||
var objects = JSON.parse(f.toString());
|
||||
if (objects['system.adapter.admin.0']) {
|
||||
console.log('checkIsControllerInstalled: installed!');
|
||||
setTimeout(function () {
|
||||
if (cb) cb();
|
||||
}, 100);
|
||||
return;
|
||||
}
|
||||
} catch (err) {
|
||||
|
||||
}
|
||||
|
||||
if (counter > 20) {
|
||||
console.log('checkIsControllerInstalled: Cannot install!');
|
||||
if (cb) cb('Cannot install');
|
||||
} else {
|
||||
console.log('checkIsControllerInstalled: wait...');
|
||||
setTimeout(function() {
|
||||
checkIsControllerInstalled(cb, counter + 1);
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
function installAdapter(customName, cb) {
|
||||
if (typeof customName === 'function') {
|
||||
cb = customName;
|
||||
customName = null;
|
||||
}
|
||||
customName = customName || pkg.name.split('.').pop();
|
||||
console.log('Install adapter...');
|
||||
var startFile = 'node_modules/' + appName + '.js-controller/' + appName + '.js';
|
||||
// make first install
|
||||
if (debug) {
|
||||
child_process.execSync('node ' + startFile + ' add ' + customName + ' --enabled false', {
|
||||
cwd: rootDir + 'tmp',
|
||||
stdio: [0, 1, 2]
|
||||
});
|
||||
checkIsAdapterInstalled(function (error) {
|
||||
if (error) console.error(error);
|
||||
console.log('Adapter installed.');
|
||||
if (cb) cb();
|
||||
});
|
||||
} else {
|
||||
// add controller
|
||||
var _pid = child_process.fork(startFile, ['add', customName, '--enabled', 'false'], {
|
||||
cwd: rootDir + 'tmp',
|
||||
stdio: [0, 1, 2, 'ipc']
|
||||
});
|
||||
|
||||
waitForEnd(_pid, function () {
|
||||
checkIsAdapterInstalled(function (error) {
|
||||
if (error) console.error(error);
|
||||
console.log('Adapter installed.');
|
||||
if (cb) cb();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function waitForEnd(_pid, cb) {
|
||||
if (!_pid) {
|
||||
cb(-1, -1);
|
||||
return;
|
||||
}
|
||||
_pid.on('exit', function (code, signal) {
|
||||
if (_pid) {
|
||||
_pid = null;
|
||||
cb(code, signal);
|
||||
}
|
||||
});
|
||||
_pid.on('close', function (code, signal) {
|
||||
if (_pid) {
|
||||
_pid = null;
|
||||
cb(code, signal);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function installJsController(cb) {
|
||||
console.log('installJsController...');
|
||||
if (!fs.existsSync(rootDir + 'tmp/node_modules/' + appName + '.js-controller') ||
|
||||
!fs.existsSync(rootDir + 'tmp/' + appName + '-data')) {
|
||||
// try to detect appName.js-controller in node_modules/appName.js-controller
|
||||
// travis CI installs js-controller into node_modules
|
||||
if (fs.existsSync(rootDir + 'node_modules/' + appName + '.js-controller')) {
|
||||
console.log('installJsController: no js-controller => copy it from "' + rootDir + 'node_modules/' + appName + '.js-controller"');
|
||||
// copy all
|
||||
// stop controller
|
||||
console.log('Stop controller if running...');
|
||||
var _pid;
|
||||
if (debug) {
|
||||
// start controller
|
||||
_pid = child_process.exec('node ' + appName + '.js stop', {
|
||||
cwd: rootDir + 'node_modules/' + appName + '.js-controller',
|
||||
stdio: [0, 1, 2]
|
||||
});
|
||||
} else {
|
||||
_pid = child_process.fork(appName + '.js', ['stop'], {
|
||||
cwd: rootDir + 'node_modules/' + appName + '.js-controller',
|
||||
stdio: [0, 1, 2, 'ipc']
|
||||
});
|
||||
}
|
||||
|
||||
waitForEnd(_pid, function () {
|
||||
// copy all files into
|
||||
if (!fs.existsSync(rootDir + 'tmp')) fs.mkdirSync(rootDir + 'tmp');
|
||||
if (!fs.existsSync(rootDir + 'tmp/node_modules')) fs.mkdirSync(rootDir + 'tmp/node_modules');
|
||||
|
||||
if (!fs.existsSync(rootDir + 'tmp/node_modules/' + appName + '.js-controller')){
|
||||
console.log('Copy js-controller...');
|
||||
copyFolderRecursiveSync(rootDir + 'node_modules/' + appName + '.js-controller', rootDir + 'tmp/node_modules/');
|
||||
}
|
||||
|
||||
console.log('Setup js-controller...');
|
||||
var __pid;
|
||||
if (debug) {
|
||||
// start controller
|
||||
_pid = child_process.exec('node ' + appName + '.js setup first --console', {
|
||||
cwd: rootDir + 'tmp/node_modules/' + appName + '.js-controller',
|
||||
stdio: [0, 1, 2]
|
||||
});
|
||||
} else {
|
||||
__pid = child_process.fork(appName + '.js', ['setup', 'first', '--console'], {
|
||||
cwd: rootDir + 'tmp/node_modules/' + appName + '.js-controller',
|
||||
stdio: [0, 1, 2, 'ipc']
|
||||
});
|
||||
}
|
||||
waitForEnd(__pid, function () {
|
||||
checkIsControllerInstalled(function () {
|
||||
// change ports for object and state DBs
|
||||
var config = require(rootDir + 'tmp/' + appName + '-data/' + appName + '.json');
|
||||
config.objects.port = 19001;
|
||||
config.states.port = 19000;
|
||||
fs.writeFileSync(rootDir + 'tmp/' + appName + '-data/' + appName + '.json', JSON.stringify(config, null, 2));
|
||||
console.log('Setup finished.');
|
||||
|
||||
copyAdapterToController();
|
||||
|
||||
installAdapter(function () {
|
||||
storeOriginalFiles();
|
||||
if (cb) cb(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// check if port 9000 is free, else admin adapter will be added to running instance
|
||||
var client = new require('net').Socket();
|
||||
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.');
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
setTimeout(function () {
|
||||
client.destroy();
|
||||
if (!fs.existsSync(rootDir + 'tmp/node_modules/' + appName + '.js-controller')) {
|
||||
console.log('installJsController: no js-controller => install from git');
|
||||
|
||||
child_process.execSync('npm install https://git.spacen.net/' + appName + '/' + appName + '.js-controller/tarball/master --prefix ./ --production', {
|
||||
cwd: rootDir + 'tmp/',
|
||||
stdio: [0, 1, 2]
|
||||
});
|
||||
} else {
|
||||
console.log('Setup js-controller...');
|
||||
var __pid;
|
||||
if (debug) {
|
||||
// start controller
|
||||
child_process.exec('node ' + appName + '.js setup first', {
|
||||
cwd: rootDir + 'tmp/node_modules/' + appName + '.js-controller',
|
||||
stdio: [0, 1, 2]
|
||||
});
|
||||
} else {
|
||||
child_process.fork(appName + '.js', ['setup', 'first'], {
|
||||
cwd: rootDir + 'tmp/node_modules/' + appName + '.js-controller',
|
||||
stdio: [0, 1, 2, 'ipc']
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// let npm install admin and run setup
|
||||
checkIsControllerInstalled(function () {
|
||||
var _pid;
|
||||
|
||||
if (fs.existsSync(rootDir + 'node_modules/' + appName + '.js-controller/' + appName + '.js')) {
|
||||
_pid = child_process.fork(appName + '.js', ['stop'], {
|
||||
cwd: rootDir + 'node_modules/' + appName + '.js-controller',
|
||||
stdio: [0, 1, 2, 'ipc']
|
||||
});
|
||||
}
|
||||
|
||||
waitForEnd(_pid, function () {
|
||||
// change ports for object and state DBs
|
||||
var config = require(rootDir + 'tmp/' + appName + '-data/' + appName + '.json');
|
||||
config.objects.port = 19001;
|
||||
config.states.port = 19000;
|
||||
fs.writeFileSync(rootDir + 'tmp/' + appName + '-data/' + appName + '.json', JSON.stringify(config, null, 2));
|
||||
|
||||
copyAdapterToController();
|
||||
|
||||
installAdapter(function () {
|
||||
storeOriginalFiles();
|
||||
if (cb) cb(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
}, 1000);
|
||||
}
|
||||
} else {
|
||||
setTimeout(function () {
|
||||
console.log('installJsController: js-controller installed');
|
||||
if (cb) cb(false);
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
function copyAdapterToController() {
|
||||
console.log('Copy adapter...');
|
||||
// Copy adapter to tmp/node_modules/appName.adapter
|
||||
copyFolderRecursiveSync(rootDir, rootDir + 'tmp/node_modules/', ['.idea', 'test', 'tmp', '.git', appName + '.js-controller']);
|
||||
console.log('Adapter copied.');
|
||||
}
|
||||
|
||||
function clearControllerLog() {
|
||||
var dirPath = rootDir + 'tmp/log';
|
||||
var files;
|
||||
try {
|
||||
if (fs.existsSync(dirPath)) {
|
||||
console.log('Clear controller log...');
|
||||
files = fs.readdirSync(dirPath);
|
||||
} else {
|
||||
console.log('Create controller log directory...');
|
||||
files = [];
|
||||
fs.mkdirSync(dirPath);
|
||||
}
|
||||
} catch(e) {
|
||||
console.error('Cannot read "' + dirPath + '"');
|
||||
return;
|
||||
}
|
||||
if (files.length > 0) {
|
||||
try {
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
var filePath = dirPath + '/' + files[i];
|
||||
fs.unlinkSync(filePath);
|
||||
}
|
||||
console.log('Controller log cleared');
|
||||
} catch (err) {
|
||||
console.error('cannot clear log: ' + err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function clearDB() {
|
||||
var dirPath = rootDir + 'tmp/yunkong2-data/sqlite';
|
||||
var files;
|
||||
try {
|
||||
if (fs.existsSync(dirPath)) {
|
||||
console.log('Clear sqlite DB...');
|
||||
files = fs.readdirSync(dirPath);
|
||||
} else {
|
||||
console.log('Create controller log directory...');
|
||||
files = [];
|
||||
fs.mkdirSync(dirPath);
|
||||
}
|
||||
} catch(e) {
|
||||
console.error('Cannot read "' + dirPath + '"');
|
||||
return;
|
||||
}
|
||||
if (files.length > 0) {
|
||||
try {
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
var filePath = dirPath + '/' + files[i];
|
||||
fs.unlinkSync(filePath);
|
||||
}
|
||||
console.log('Clear sqlite DB');
|
||||
} catch (err) {
|
||||
console.error('cannot clear DB: ' + err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setupController(cb) {
|
||||
installJsController(function (isInited) {
|
||||
clearControllerLog();
|
||||
clearDB();
|
||||
|
||||
if (!isInited) {
|
||||
restoreOriginalFiles();
|
||||
copyAdapterToController();
|
||||
}
|
||||
// read system.config object
|
||||
var dataDir = rootDir + 'tmp/' + appName + '-data/';
|
||||
|
||||
var objs;
|
||||
try {
|
||||
objs = fs.readFileSync(dataDir + 'objects.json');
|
||||
objs = JSON.parse(objs);
|
||||
}
|
||||
catch (e) {
|
||||
console.log('ERROR reading/parsing system configuration. Ignore');
|
||||
objs = {'system.config': {}};
|
||||
}
|
||||
if (!objs || !objs['system.config']) {
|
||||
objs = {'system.config': {}};
|
||||
}
|
||||
|
||||
if (cb) cb(objs['system.config']);
|
||||
});
|
||||
}
|
||||
|
||||
function startAdapter(objects, states, callback) {
|
||||
if (adapterStarted) {
|
||||
console.log('Adapter already started ...');
|
||||
if (callback) callback(objects, states);
|
||||
return;
|
||||
}
|
||||
adapterStarted = true;
|
||||
console.log('startAdapter...');
|
||||
if (fs.existsSync(rootDir + 'tmp/node_modules/' + pkg.name + '/' + pkg.main)) {
|
||||
try {
|
||||
if (debug) {
|
||||
// start controller
|
||||
pid = child_process.exec('node node_modules/' + pkg.name + '/' + pkg.main + ' --console silly', {
|
||||
cwd: rootDir + 'tmp',
|
||||
stdio: [0, 1, 2]
|
||||
});
|
||||
} else {
|
||||
// start controller
|
||||
pid = child_process.fork('node_modules/' + pkg.name + '/' + pkg.main, ['--console', 'silly'], {
|
||||
cwd: rootDir + 'tmp',
|
||||
stdio: [0, 1, 2, 'ipc']
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(JSON.stringify(error));
|
||||
}
|
||||
} else {
|
||||
console.error('Cannot find: ' + rootDir + 'tmp/node_modules/' + pkg.name + '/' + pkg.main);
|
||||
}
|
||||
if (callback) callback(objects, states);
|
||||
}
|
||||
|
||||
function startController(isStartAdapter, onObjectChange, onStateChange, callback) {
|
||||
if (typeof isStartAdapter === 'function') {
|
||||
callback = onStateChange;
|
||||
onStateChange = onObjectChange;
|
||||
onObjectChange = isStartAdapter;
|
||||
isStartAdapter = true;
|
||||
}
|
||||
|
||||
if (onStateChange === undefined) {
|
||||
callback = onObjectChange;
|
||||
onObjectChange = undefined;
|
||||
}
|
||||
|
||||
if (pid) {
|
||||
console.error('Controller is already started!');
|
||||
} else {
|
||||
console.log('startController...');
|
||||
adapterStarted = false;
|
||||
var isObjectConnected;
|
||||
var isStatesConnected;
|
||||
|
||||
var Objects = require(rootDir + 'tmp/node_modules/' + appName + '.js-controller/lib/objects/objectsInMemServer');
|
||||
objects = new Objects({
|
||||
connection: {
|
||||
"type" : "file",
|
||||
"host" : "127.0.0.1",
|
||||
"port" : 19001,
|
||||
"user" : "",
|
||||
"pass" : "",
|
||||
"noFileCache": false,
|
||||
"connectTimeout": 2000
|
||||
},
|
||||
logger: {
|
||||
silly: function (msg) {
|
||||
console.log(msg);
|
||||
},
|
||||
debug: function (msg) {
|
||||
console.log(msg);
|
||||
},
|
||||
info: function (msg) {
|
||||
console.log(msg);
|
||||
},
|
||||
warn: function (msg) {
|
||||
console.warn(msg);
|
||||
},
|
||||
error: function (msg) {
|
||||
console.error(msg);
|
||||
}
|
||||
},
|
||||
connected: function () {
|
||||
isObjectConnected = true;
|
||||
if (isStatesConnected) {
|
||||
console.log('startController: started!');
|
||||
if (isStartAdapter) {
|
||||
startAdapter(objects, states, callback);
|
||||
} else {
|
||||
if (callback) {
|
||||
callback(objects, states);
|
||||
callback = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
change: onObjectChange
|
||||
});
|
||||
|
||||
// Just open in memory DB itself
|
||||
var States = require(rootDir + 'tmp/node_modules/' + appName + '.js-controller/lib/states/statesInMemServer');
|
||||
states = new States({
|
||||
connection: {
|
||||
type: 'file',
|
||||
host: '127.0.0.1',
|
||||
port: 19000,
|
||||
options: {
|
||||
auth_pass: null,
|
||||
retry_max_delay: 15000
|
||||
}
|
||||
},
|
||||
logger: {
|
||||
silly: function (msg) {
|
||||
console.log(msg);
|
||||
},
|
||||
debug: function (msg) {
|
||||
console.log(msg);
|
||||
},
|
||||
info: function (msg) {
|
||||
console.log(msg);
|
||||
},
|
||||
warn: function (msg) {
|
||||
console.log(msg);
|
||||
},
|
||||
error: function (msg) {
|
||||
console.log(msg);
|
||||
}
|
||||
},
|
||||
connected: function () {
|
||||
isStatesConnected = true;
|
||||
if (isObjectConnected) {
|
||||
console.log('startController: started!!');
|
||||
if (isStartAdapter) {
|
||||
startAdapter(objects, states, callback);
|
||||
} else {
|
||||
if (callback) {
|
||||
callback(objects, states);
|
||||
callback = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
change: onStateChange
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function stopAdapter(cb) {
|
||||
if (!pid) {
|
||||
console.error('Controller is not running!');
|
||||
if (cb) {
|
||||
setTimeout(function () {
|
||||
cb(false);
|
||||
}, 0);
|
||||
}
|
||||
} else {
|
||||
adapterStarted = false;
|
||||
pid.on('exit', function (code, signal) {
|
||||
if (pid) {
|
||||
console.log('child process terminated due to receipt of signal ' + signal);
|
||||
if (cb) cb();
|
||||
pid = null;
|
||||
}
|
||||
});
|
||||
|
||||
pid.on('close', function (code, signal) {
|
||||
if (pid) {
|
||||
if (cb) cb();
|
||||
pid = null;
|
||||
}
|
||||
});
|
||||
|
||||
pid.kill('SIGTERM');
|
||||
}
|
||||
}
|
||||
|
||||
function _stopController() {
|
||||
if (objects) {
|
||||
objects.destroy();
|
||||
objects = null;
|
||||
}
|
||||
if (states) {
|
||||
states.destroy();
|
||||
states = null;
|
||||
}
|
||||
}
|
||||
|
||||
function stopController(cb) {
|
||||
var timeout;
|
||||
if (objects) {
|
||||
console.log('Set system.adapter.' + pkg.name + '.0');
|
||||
objects.setObject('system.adapter.' + pkg.name + '.0', {
|
||||
common:{
|
||||
enabled: false
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
stopAdapter(function () {
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
timeout = null;
|
||||
}
|
||||
|
||||
_stopController();
|
||||
|
||||
if (cb) {
|
||||
cb(true);
|
||||
cb = null;
|
||||
}
|
||||
});
|
||||
|
||||
timeout = setTimeout(function () {
|
||||
timeout = null;
|
||||
console.log('child process NOT terminated');
|
||||
|
||||
_stopController();
|
||||
|
||||
if (cb) {
|
||||
cb(false);
|
||||
cb = null;
|
||||
}
|
||||
pid = null;
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
// Setup the adapter
|
||||
function setAdapterConfig(common, native, instance) {
|
||||
var objects = JSON.parse(fs.readFileSync(rootDir + 'tmp/' + appName + '-data/objects.json').toString());
|
||||
var id = 'system.adapter.' + adapterName.split('.').pop() + '.' + (instance || 0);
|
||||
if (common) objects[id].common = common;
|
||||
if (native) objects[id].native = native;
|
||||
fs.writeFileSync(rootDir + 'tmp/' + appName + '-data/objects.json', JSON.stringify(objects));
|
||||
}
|
||||
|
||||
// Read config of the adapter
|
||||
function getAdapterConfig(instance) {
|
||||
var objects = JSON.parse(fs.readFileSync(rootDir + 'tmp/' + appName + '-data/objects.json').toString());
|
||||
var id = 'system.adapter.' + adapterName.split('.').pop() + '.' + (instance || 0);
|
||||
return objects[id];
|
||||
}
|
||||
|
||||
if (typeof module !== undefined && module.parent) {
|
||||
module.exports.getAdapterConfig = getAdapterConfig;
|
||||
module.exports.setAdapterConfig = setAdapterConfig;
|
||||
module.exports.startController = startController;
|
||||
module.exports.stopController = stopController;
|
||||
module.exports.setupController = setupController;
|
||||
module.exports.stopAdapter = stopAdapter;
|
||||
module.exports.startAdapter = startAdapter;
|
||||
module.exports.installAdapter = installAdapter;
|
||||
module.exports.appName = appName;
|
||||
module.exports.adapterName = adapterName;
|
||||
module.exports.adapterStarted = adapterStarted;
|
||||
}
|
||||
397
test/testMSSQL.js
Normal file
397
test/testMSSQL.js
Normal file
@@ -0,0 +1,397 @@
|
||||
/* jshint -W097 */// jshint strict:false
|
||||
/*jslint node: true */
|
||||
/*jshint expr: true*/
|
||||
var expect = require('chai').expect;
|
||||
var setup = require(__dirname + '/lib/setup');
|
||||
|
||||
var objects = null;
|
||||
var states = null;
|
||||
var onStateChanged = null;
|
||||
var onObjectChanged = null;
|
||||
var sendToID = 1;
|
||||
|
||||
var adapterShortName = setup.adapterName.substring(setup.adapterName.indexOf('.')+1);
|
||||
|
||||
var now = new Date().getTime();
|
||||
|
||||
function checkConnectionOfAdapter(cb, counter) {
|
||||
counter = counter || 0;
|
||||
if (counter > 20) {
|
||||
cb && cb('Cannot check connection');
|
||||
return;
|
||||
}
|
||||
|
||||
states.getState('system.adapter.' + adapterShortName + '.0.alive', function (err, state) {
|
||||
if (err) console.error('MSSQL: ' + err);
|
||||
if (state && state.val) {
|
||||
cb && cb();
|
||||
} else {
|
||||
setTimeout(function () {
|
||||
checkConnectionOfAdapter(cb, counter + 1);
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function checkValueOfState(id, value, cb, counter) {
|
||||
counter = counter || 0;
|
||||
if (counter > 20) {
|
||||
cb && cb('Cannot check value Of State ' + id);
|
||||
return;
|
||||
}
|
||||
|
||||
states.getState(id, function (err, state) {
|
||||
if (err) console.error('MSSQL: ' + err);
|
||||
if (value === null && !state) {
|
||||
cb && cb();
|
||||
} else
|
||||
if (state && (value === undefined || state.val === value)) {
|
||||
cb && cb();
|
||||
} else {
|
||||
setTimeout(function () {
|
||||
checkValueOfState(id, value, cb, counter + 1);
|
||||
}, 500);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function sendTo(target, command, message, callback) {
|
||||
onStateChanged = function (id, state) {
|
||||
if (id === 'messagebox.system.adapter.test.0') {
|
||||
callback(state.message);
|
||||
}
|
||||
};
|
||||
|
||||
states.pushMessage('system.adapter.' + target, {
|
||||
command: command,
|
||||
message: message,
|
||||
from: 'system.adapter.test.0',
|
||||
callback: {
|
||||
message: message,
|
||||
id: sendToID++,
|
||||
ack: false,
|
||||
time: (new Date()).getTime()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
describe('Test MSSQL', function() {
|
||||
before('Test MSSQL: Start js-controller', function (_done) {
|
||||
this.timeout(600000); // because of first install from npm
|
||||
setup.adapterStarted = false;
|
||||
|
||||
console.log('Started in TRAVIS: ' + (process.env.TRAVIS && process.env.TRAVIS==='true'));
|
||||
console.log('Started in APPVEYOR: ' + (process.env.APPVEYOR && process.env.APPVEYOR==='True'));
|
||||
|
||||
if (!(process.env.APPVEYOR && process.env.APPVEYOR==='True')) {
|
||||
console.log('MSSQL testing only available in Appveyor on Windows, ignore test run (APPVEYOR:' + JSON.stringify(process.env.APPVEYOR) + ', TRAVIS:' + JSON.stringify(process.env.TRAVIS) + ')');
|
||||
_done();
|
||||
return;
|
||||
}
|
||||
setup.setupController(function () {
|
||||
var config = setup.getAdapterConfig();
|
||||
// enable adapter
|
||||
config.common.enabled = true;
|
||||
config.common.loglevel = 'debug';
|
||||
|
||||
config.native.dbtype = 'mssql';
|
||||
config.native.user = 'sa';
|
||||
config.native.password = 'Password12!';
|
||||
|
||||
setup.setAdapterConfig(config.common, config.native);
|
||||
|
||||
setup.startController(true, function(id, obj) {}, function (id, state) {
|
||||
if (onStateChanged) onStateChanged(id, state);
|
||||
},
|
||||
function (_objects, _states) {
|
||||
objects = _objects;
|
||||
states = _states;
|
||||
objects.setObject('sql.0.memRss', {
|
||||
common: {
|
||||
type: 'number',
|
||||
role: 'state',
|
||||
custom: {
|
||||
"sql.0": {
|
||||
enabled: true,
|
||||
changesOnly: true,
|
||||
debounce: 0,
|
||||
retention: 31536000,
|
||||
maxLength: 3,
|
||||
changesMinDelta: 0.5
|
||||
}
|
||||
}
|
||||
},
|
||||
type: 'state'
|
||||
}, _done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Test MSSQL: Check if adapter started', function (done) {
|
||||
this.timeout(60000);
|
||||
if (!(process.env.APPVEYOR && process.env.APPVEYOR==='True')) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
checkConnectionOfAdapter(function () {
|
||||
now = new Date().getTime();
|
||||
objects.setObject('system.adapter.test.0', {
|
||||
common: {
|
||||
|
||||
},
|
||||
type: 'instance'
|
||||
},
|
||||
function () {
|
||||
states.subscribeMessage('system.adapter.test.0');
|
||||
setTimeout(function () {
|
||||
sendTo('sql.0', 'enableHistory', {
|
||||
id: 'sql.0.memRss',
|
||||
options: {
|
||||
changesOnly: true,
|
||||
debounce: 0,
|
||||
retention: 31536000,
|
||||
changesMinDelta: 0.5,
|
||||
storageType: 'Number'
|
||||
}
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
sendTo('sql.0', 'enableHistory', {
|
||||
id: 'system.adapter.sql.0.memHeapTotal',
|
||||
options: {
|
||||
changesOnly: false,
|
||||
debounce: 0,
|
||||
retention: 31536000,
|
||||
storageType: 'String'
|
||||
}
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
sendTo('sql.0', 'enableHistory', {
|
||||
id: 'system.adapter.sql.0.uptime',
|
||||
options: {
|
||||
changesOnly: false,
|
||||
debounce: 0,
|
||||
retention: 31536000,
|
||||
storageType: 'Boolean'
|
||||
}
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
// wait till adapter receives the new settings
|
||||
setTimeout(function () {
|
||||
done();
|
||||
}, 20000);
|
||||
});
|
||||
});
|
||||
});
|
||||
}, 10000);
|
||||
});
|
||||
});
|
||||
});
|
||||
it('Test ' + adapterShortName + ': Check Enabled Points after Enable', function (done) {
|
||||
this.timeout(20000);
|
||||
if (!(process.env.APPVEYOR && process.env.APPVEYOR==='True')) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
sendTo('sql.0', 'getEnabledDPs', {}, function (result) {
|
||||
console.log(JSON.stringify(result));
|
||||
expect(Object.keys(result).length).to.be.equal(3);
|
||||
expect(result['sql.0.memRss'].enabled).to.be.true;
|
||||
setTimeout(function () {
|
||||
done();
|
||||
}, 15000);
|
||||
});
|
||||
});
|
||||
it('Test MSSQL: Write values into DB', function (done) {
|
||||
this.timeout(10000);
|
||||
if (!(process.env.APPVEYOR && process.env.APPVEYOR==='True')) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
this.timeout(10000);
|
||||
|
||||
states.setState('sql.0.memRss', {val: 2, ts: now - 20000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: true, ts: now - 10000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: 2, ts: now - 5000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: 2.2, ts: now - 4000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: '2.5', ts: now - 3000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: 3, ts: now - 1000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: 'Test', ts: now - 500}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(done, 5000);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
it('Test MSSQL: Read values from DB using query', function (done) {
|
||||
this.timeout(10000);
|
||||
if (!(process.env.APPVEYOR && process.env.APPVEYOR==='True')) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
sendTo('sql.0', 'query', "SELECT id FROM yunkong2.dbo.datapoints WHERE name='sql.0.memRss'", function (result) {
|
||||
sendTo('sql.0', 'query', 'SELECT * FROM yunkong2.dbo.ts_number WHERE id=' + result.result[0].id, function (result) {
|
||||
console.log('MSSQL: ' + JSON.stringify(result.result, null, 2));
|
||||
expect(result.result.length).to.be.at.least(5);
|
||||
var found = 0;
|
||||
for (var i = 0; i < result.result.length; i++) {
|
||||
if (result.result[i].val >= 1 && result.result[i].val <= 3) found ++;
|
||||
}
|
||||
expect(found).to.be.equal(6);
|
||||
|
||||
setTimeout(function () {
|
||||
done();
|
||||
}, 3000);
|
||||
});
|
||||
});
|
||||
});
|
||||
it('Test MSSQL: Read values from DB using GetHistory', function (done) {
|
||||
this.timeout(10000);
|
||||
if (!(process.env.APPVEYOR && process.env.APPVEYOR==='True')) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
sendTo('sql.0', 'getHistory', {
|
||||
id: 'sql.0.memRss',
|
||||
options: {
|
||||
start: now - 30000,
|
||||
limit: 50,
|
||||
count: 50,
|
||||
aggregate: 'none'
|
||||
}
|
||||
}, function (result) {
|
||||
console.log('MSSQL: ' + JSON.stringify(result.result, null, 2));
|
||||
expect(result.result.length).to.be.at.least(5);
|
||||
var found = 0;
|
||||
for (var i = 0; i < result.result.length; i++) {
|
||||
if (result.result[i].val >= 1 && result.result[i].val <= 3) found ++;
|
||||
}
|
||||
expect(found).to.be.equal(6);
|
||||
|
||||
sendTo('sql.0', 'getHistory', {
|
||||
id: 'sql.0.memRss',
|
||||
options: {
|
||||
start: now - 15000,
|
||||
end: now,
|
||||
limit: 2,
|
||||
count: 2,
|
||||
aggregate: 'none'
|
||||
}
|
||||
}, function (result) {
|
||||
console.log('MSSQL: ' + JSON.stringify(result.result, null, 2));
|
||||
expect(result.result.length).to.be.equal(2);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
it('Test ' + adapterShortName + ': Check Datapoint Types', function (done) {
|
||||
this.timeout(5000);
|
||||
if (!(process.env.APPVEYOR && process.env.APPVEYOR==='True')) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
sendTo('sql.0', 'query', "SELECT name, type FROM yunkong2.dbo.datapoints", function (result) {
|
||||
console.log('MSSQL: ' + JSON.stringify(result.result, null, 2));
|
||||
expect(result.result.length).to.least(3);
|
||||
for (var i = 0; i < result.result.length; i++) {
|
||||
if (result.result[i].name === 'sql.0.memRss') {
|
||||
expect(result.result[i].type).to.be.equal(0);
|
||||
}
|
||||
else if (result.result[i].name === 'system.adapter.sql.0.memHeapTotal') {
|
||||
expect(result.result[i].type).to.be.equal(1);
|
||||
}
|
||||
else if (result.result[i].name === 'system.adapter.sql.0.uptime') {
|
||||
expect(result.result[i].type).to.be.equal(2);
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
done();
|
||||
}, 3000);
|
||||
});
|
||||
});
|
||||
it('Test ' + adapterShortName + ': Disable Datapoint again', function (done) {
|
||||
this.timeout(5000);
|
||||
if (!(process.env.APPVEYOR && process.env.APPVEYOR==='True')) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
sendTo('sql.0', 'disableHistory', {
|
||||
id: 'sql.0.memRss',
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
setTimeout(done, 2000);
|
||||
});
|
||||
});
|
||||
it('Test ' + adapterShortName + ': Check Enabled Points after Disable', function (done) {
|
||||
this.timeout(5000);
|
||||
if (!(process.env.APPVEYOR && process.env.APPVEYOR==='True')) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
sendTo('sql.0', 'getEnabledDPs', {}, function (result) {
|
||||
console.log(JSON.stringify(result));
|
||||
expect(Object.keys(result).length).to.be.equal(2);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
after('Test MSSQL: Stop js-controller', function (done) {
|
||||
this.timeout(6000);
|
||||
if (!(process.env.APPVEYOR && process.env.APPVEYOR==='True')) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
setup.stopController(function (normalTerminated) {
|
||||
console.log('MSSQL: Adapter normal terminated: ' + normalTerminated);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
374
test/testMySQL.js
Normal file
374
test/testMySQL.js
Normal file
@@ -0,0 +1,374 @@
|
||||
/* jshint -W097 */// jshint strict:false
|
||||
/*jslint node: true */
|
||||
/*jshint expr: true*/
|
||||
var expect = require('chai').expect;
|
||||
var setup = require(__dirname + '/lib/setup');
|
||||
|
||||
var objects = null;
|
||||
var states = null;
|
||||
var onStateChanged = null;
|
||||
var onObjectChanged = null;
|
||||
var sendToID = 1;
|
||||
|
||||
var adapterShortName = setup.adapterName.substring(setup.adapterName.indexOf('.')+1);
|
||||
|
||||
var now = new Date().getTime();
|
||||
|
||||
function checkConnectionOfAdapter(cb, counter) {
|
||||
counter = counter || 0;
|
||||
if (counter > 20) {
|
||||
cb && cb('Cannot check connection');
|
||||
return;
|
||||
}
|
||||
|
||||
states.getState('system.adapter.' + adapterShortName + '.0.alive', function (err, state) {
|
||||
if (err) console.error('MySQL: ' + err);
|
||||
if (state && state.val) {
|
||||
cb && cb();
|
||||
} else {
|
||||
setTimeout(function () {
|
||||
checkConnectionOfAdapter(cb, counter + 1);
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function checkValueOfState(id, value, cb, counter) {
|
||||
counter = counter || 0;
|
||||
if (counter > 20) {
|
||||
cb && cb('Cannot check value Of State ' + id);
|
||||
return;
|
||||
}
|
||||
|
||||
states.getState(id, function (err, state) {
|
||||
if (err) console.error('MySQL: ' + err);
|
||||
if (value === null && !state) {
|
||||
cb && cb();
|
||||
} else
|
||||
if (state && (value === undefined || state.val === value)) {
|
||||
cb && cb();
|
||||
} else {
|
||||
setTimeout(function () {
|
||||
checkValueOfState(id, value, cb, counter + 1);
|
||||
}, 500);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function sendTo(target, command, message, callback) {
|
||||
onStateChanged = function (id, state) {
|
||||
if (id === 'messagebox.system.adapter.test.0') {
|
||||
callback(state.message);
|
||||
}
|
||||
};
|
||||
|
||||
states.pushMessage('system.adapter.' + target, {
|
||||
command: command,
|
||||
message: message,
|
||||
from: 'system.adapter.test.0',
|
||||
callback: {
|
||||
message: message,
|
||||
id: sendToID++,
|
||||
ack: false,
|
||||
time: (new Date()).getTime()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
describe('Test MySQL', function() {
|
||||
before('Test MySQL: Start js-controller', function (_done) {
|
||||
this.timeout(600000); // because of first install from npm
|
||||
setup.adapterStarted = false;
|
||||
|
||||
setup.setupController(function () {
|
||||
var config = setup.getAdapterConfig();
|
||||
// enable adapter
|
||||
config.common.enabled = true;
|
||||
config.common.loglevel = 'debug';
|
||||
|
||||
config.native.dbtype = 'mysql';
|
||||
config.native.user = 'root';
|
||||
if (process.env.APPVEYOR && process.env.APPVEYOR==='True') {
|
||||
config.native.password = 'Password12!';
|
||||
}
|
||||
|
||||
setup.setAdapterConfig(config.common, config.native);
|
||||
|
||||
setup.startController(true, function(id, obj) {}, function (id, state) {
|
||||
if (onStateChanged) onStateChanged(id, state);
|
||||
},
|
||||
function (_objects, _states) {
|
||||
objects = _objects;
|
||||
states = _states;
|
||||
objects.setObject('sql.0.memRss', {
|
||||
common: {
|
||||
type: 'number',
|
||||
role: 'state',
|
||||
custom: {
|
||||
"sql.0": {
|
||||
enabled: true,
|
||||
changesOnly: true,
|
||||
debounce: 0,
|
||||
retention: 31536000,
|
||||
maxLength: 3,
|
||||
changesMinDelta: 0.5
|
||||
}
|
||||
}
|
||||
},
|
||||
type: 'state'
|
||||
}, _done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Test MySQL: Check if adapter started', function (done) {
|
||||
this.timeout(90000);
|
||||
checkConnectionOfAdapter(function () {
|
||||
now = new Date().getTime();
|
||||
objects.setObject('system.adapter.test.0', {
|
||||
common: {
|
||||
|
||||
},
|
||||
type: 'instance'
|
||||
},
|
||||
function () {
|
||||
states.subscribeMessage('system.adapter.test.0');
|
||||
setTimeout(function () {
|
||||
sendTo('sql.0', 'enableHistory', {
|
||||
id: 'system.adapter.sql.0.memHeapTotal',
|
||||
options: {
|
||||
changesOnly: false,
|
||||
debounce: 0,
|
||||
retention: 31536000,
|
||||
storageType: 'String'
|
||||
}
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
sendTo('sql.0', 'enableHistory', {
|
||||
id: 'system.adapter.sql.0.alive',
|
||||
options: {
|
||||
changesOnly: false,
|
||||
debounce: 0,
|
||||
retention: 31536000,
|
||||
storageType: 'Boolean'
|
||||
}
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
sendTo('sql.0', 'enableHistory', {
|
||||
id: 'system.adapter.sql.0.uptime',
|
||||
options: {
|
||||
changesOnly: false,
|
||||
debounce: 0,
|
||||
retention: 31536000,
|
||||
storageType: false
|
||||
}
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
// wait till adapter receives the new settings
|
||||
setTimeout(function () {
|
||||
done();
|
||||
}, 70000);
|
||||
});
|
||||
});
|
||||
});
|
||||
}, 10000);
|
||||
});
|
||||
});
|
||||
});
|
||||
it('Test ' + adapterShortName + ': Check Enabled Points after Enable', function (done) {
|
||||
this.timeout(20000);
|
||||
|
||||
sendTo('sql.0', 'getEnabledDPs', {}, function (result) {
|
||||
console.log(JSON.stringify(result));
|
||||
expect(Object.keys(result).length).to.be.equal(4);
|
||||
expect(result['sql.0.memRss'].enabled).to.be.true;
|
||||
setTimeout(function () {
|
||||
done();
|
||||
}, 15000);
|
||||
});
|
||||
});
|
||||
it('Test MySQL: Write values into DB', function (done) {
|
||||
this.timeout(10000);
|
||||
|
||||
states.setState('sql.0.memRss', {val: 2, ts: now - 20000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: true, ts: now - 10000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: 2, ts: now - 5000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: 2.2, ts: now - 4000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: 2.3, ts: now - 3500}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: '2.5', ts: now - 3000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: 3, ts: now - 1000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: 'Test', ts: now - 500}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(done, 5000);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
it('Test MySQL: Read values from DB using query', function (done) {
|
||||
this.timeout(10000);
|
||||
|
||||
sendTo('sql.0', 'query', 'SELECT id FROM yunkong2.datapoints WHERE name="sql.0.memRss"', function (result) {
|
||||
console.log('MySQL: ' + JSON.stringify(result.result, null, 2));
|
||||
sendTo('sql.0', 'query', 'SELECT * FROM yunkong2.ts_number WHERE id=' + result.result[0].id, function (result) {
|
||||
console.log('MySQL: ' + JSON.stringify(result.result, null, 2));
|
||||
expect(result.result.length).to.be.at.least(5);
|
||||
var found = 0;
|
||||
var found22 = false;
|
||||
var found23 = false;
|
||||
for (var i = 0; i < result.result.length; i++) {
|
||||
if (result.result[i].val >= 1 && result.result[i].val <= 3) found ++;
|
||||
if (result.result[i].val === 2.2) found22 = true;
|
||||
if (result.result[i].val === 2.3) found23 = true;
|
||||
}
|
||||
expect(found).to.be.equal(6);
|
||||
expect(found22).to.be.false;
|
||||
expect(found23).to.be.true;
|
||||
|
||||
setTimeout(function () {
|
||||
done();
|
||||
}, 3000);
|
||||
});
|
||||
});
|
||||
});
|
||||
it('Test MySQL: Read values from DB using GetHistory', function (done) {
|
||||
this.timeout(10000);
|
||||
|
||||
sendTo('sql.0', 'getHistory', {
|
||||
id: 'sql.0.memRss',
|
||||
options: {
|
||||
start: now - 30000,
|
||||
limit: 50,
|
||||
count: 50,
|
||||
aggregate: 'none'
|
||||
}
|
||||
}, function (result) {
|
||||
console.log('MySQL: ' + JSON.stringify(result.result, null, 2));
|
||||
expect(result.result.length).to.be.at.least(5);
|
||||
var found = 0;
|
||||
for (var i = 0; i < result.result.length; i++) {
|
||||
if (result.result[i].val >= 1 && result.result[i].val <= 3) found ++;
|
||||
}
|
||||
expect(found).to.be.equal(6);
|
||||
|
||||
sendTo('sql.0', 'getHistory', {
|
||||
id: 'sql.0.memRss',
|
||||
options: {
|
||||
start: now - 15000,
|
||||
end: now,
|
||||
limit: 2,
|
||||
count: 2,
|
||||
aggregate: 'none'
|
||||
}
|
||||
}, function (result) {
|
||||
console.log('MySQL: ' + JSON.stringify(result.result, null, 2));
|
||||
expect(result.result.length).to.be.equal(2);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
it('Test ' + adapterShortName + ': Check Datapoint Types', function (done) {
|
||||
this.timeout(5000);
|
||||
|
||||
sendTo('sql.0', 'query', "SELECT id, name, type FROM yunkong2.datapoints", function (result) {
|
||||
console.log('MySQL: ' + JSON.stringify(result.result, null, 2));
|
||||
expect(result.result.length).to.least(3);
|
||||
var uptime_id = null;
|
||||
for (var i = 0; i < result.result.length; i++) {
|
||||
if (result.result[i].name === 'sql.0.memRss') {
|
||||
expect(result.result[i].type).to.be.equal(0);
|
||||
}
|
||||
else if (result.result[i].name === 'system.adapter.sql.0.memHeapTotal') {
|
||||
expect(result.result[i].type).to.be.equal(1);
|
||||
}
|
||||
else if (result.result[i].name === 'system.adapter.sql.0.alive') {
|
||||
expect(result.result[i].type).to.be.equal(2);
|
||||
}
|
||||
else if (result.result[i].name === 'system.adapter.sql.0.uptime') {
|
||||
expect(result.result[i].type).to.be.equal(0);
|
||||
uptime_id = result.result[i].id;
|
||||
expect(uptime_id).to.be.not.null;
|
||||
}
|
||||
}
|
||||
|
||||
sendTo('sql.0', 'query', "UPDATE yunkong2.datapoints SET type=NULL WHERE id=" + uptime_id, function (result) {
|
||||
console.log('MySQL: ' + JSON.stringify(result.result, null, 2));
|
||||
expect(result.result.affectedRows).to.be.equal(1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
it('Test ' + adapterShortName + ': Disable Datapoint again', function (done) {
|
||||
this.timeout(5000);
|
||||
|
||||
sendTo('sql.0', 'disableHistory', {
|
||||
id: 'sql.0.memRss',
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
setTimeout(done, 2000);
|
||||
});
|
||||
});
|
||||
it('Test ' + adapterShortName + ': Check Enabled Points after Disable', function (done) {
|
||||
this.timeout(5000);
|
||||
|
||||
sendTo('sql.0', 'getEnabledDPs', {}, function (result) {
|
||||
console.log(JSON.stringify(result));
|
||||
expect(Object.keys(result).length).to.be.equal(3);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
after('Test MySQL: Stop js-controller', function (done) {
|
||||
this.timeout(6000);
|
||||
|
||||
setup.stopController(function (normalTerminated) {
|
||||
console.log('MySQL: Adapter normal terminated: ' + normalTerminated);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
482
test/testMySQLDash.js
Normal file
482
test/testMySQLDash.js
Normal file
@@ -0,0 +1,482 @@
|
||||
/* jshint -W097 */// jshint strict:false
|
||||
/*jslint node: true */
|
||||
/*jshint expr: true*/
|
||||
var expect = require('chai').expect;
|
||||
var setup = require(__dirname + '/lib/setup');
|
||||
|
||||
var objects = null;
|
||||
var states = null;
|
||||
var onStateChanged = null;
|
||||
var onObjectChanged = null;
|
||||
var sendToID = 1;
|
||||
|
||||
var adapterShortName = setup.adapterName.substring(setup.adapterName.indexOf('.')+1);
|
||||
|
||||
var now = new Date().getTime();
|
||||
|
||||
function checkConnectionOfAdapter(cb, counter) {
|
||||
counter = counter || 0;
|
||||
if (counter > 20) {
|
||||
cb && cb('Cannot check connection');
|
||||
return;
|
||||
}
|
||||
|
||||
states.getState('system.adapter.' + adapterShortName + '.0.alive', function (err, state) {
|
||||
if (err) console.error('MySQL-with-dash: ' + err);
|
||||
if (state && state.val) {
|
||||
cb && cb();
|
||||
} else {
|
||||
setTimeout(function () {
|
||||
checkConnectionOfAdapter(cb, counter + 1);
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function checkValueOfState(id, value, cb, counter) {
|
||||
counter = counter || 0;
|
||||
if (counter > 20) {
|
||||
cb && cb('Cannot check value Of State ' + id);
|
||||
return;
|
||||
}
|
||||
|
||||
states.getState(id, function (err, state) {
|
||||
if (err) console.error('MySQL-with-dash: ' + err);
|
||||
if (value === null && !state) {
|
||||
cb && cb();
|
||||
} else
|
||||
if (state && (value === undefined || state.val === value)) {
|
||||
cb && cb();
|
||||
} else {
|
||||
setTimeout(function () {
|
||||
checkValueOfState(id, value, cb, counter + 1);
|
||||
}, 500);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function sendTo(target, command, message, callback) {
|
||||
onStateChanged = function (id, state) {
|
||||
if (id === 'messagebox.system.adapter.test.0') {
|
||||
callback(state.message);
|
||||
}
|
||||
};
|
||||
|
||||
states.pushMessage('system.adapter.' + target, {
|
||||
command: command,
|
||||
message: message,
|
||||
from: 'system.adapter.test.0',
|
||||
callback: {
|
||||
message: message,
|
||||
id: sendToID++,
|
||||
ack: false,
|
||||
time: (new Date()).getTime()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
describe('Test MySQL-with-dash', function() {
|
||||
before('Test MySQL-with-dash: Start js-controller', function (_done) {
|
||||
this.timeout(600000); // because of first install from npm
|
||||
setup.adapterStarted = false;
|
||||
|
||||
setup.setupController(function () {
|
||||
var config = setup.getAdapterConfig();
|
||||
// enable adapter
|
||||
config.common.enabled = true;
|
||||
config.common.loglevel = 'debug';
|
||||
|
||||
config.native.dbtype = 'mysql';
|
||||
config.native.user = 'root';
|
||||
config.native.dbname = 'io-broker';
|
||||
if (process.env.APPVEYOR && process.env.APPVEYOR==='True') {
|
||||
config.native.password = 'Password12!';
|
||||
}
|
||||
|
||||
setup.setAdapterConfig(config.common, config.native);
|
||||
|
||||
setup.startController(true, function(id, obj) {}, function (id, state) {
|
||||
if (onStateChanged) onStateChanged(id, state);
|
||||
},
|
||||
function (_objects, _states) {
|
||||
objects = _objects;
|
||||
states = _states;
|
||||
objects.setObject('sql.0.memRss', {
|
||||
common: {
|
||||
type: 'number',
|
||||
role: 'state',
|
||||
custom: {
|
||||
"sql.0": {
|
||||
enabled: true,
|
||||
changesOnly: true,
|
||||
debounce: 0,
|
||||
retention: 31536000,
|
||||
maxLength: 3,
|
||||
changesMinDelta: 0.5
|
||||
}
|
||||
}
|
||||
},
|
||||
type: 'state'
|
||||
}, _done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Test MySQL-with-dash: Check if adapter started', function (done) {
|
||||
this.timeout(60000);
|
||||
checkConnectionOfAdapter(function () {
|
||||
now = new Date().getTime();
|
||||
objects.setObject('system.adapter.test.0', {
|
||||
common: {
|
||||
|
||||
},
|
||||
type: 'instance'
|
||||
},
|
||||
function () {
|
||||
states.subscribeMessage('system.adapter.test.0');
|
||||
setTimeout(function () {
|
||||
sendTo('sql.0', 'enableHistory', {
|
||||
id: 'system.adapter.sql.0.memHeapTotal',
|
||||
options: {
|
||||
changesOnly: false,
|
||||
debounce: 0,
|
||||
retention: 31536000,
|
||||
storageType: false
|
||||
}
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
sendTo('sql.0', 'enableHistory', {
|
||||
id: 'system.adapter.sql.0.uptime',
|
||||
options: {
|
||||
changesOnly: false,
|
||||
debounce: 0,
|
||||
retention: 31536000,
|
||||
storageType: false
|
||||
}
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
sendTo('sql.0', 'enableHistory', {
|
||||
id: 'system.adapter.sql.0.alive',
|
||||
options: {
|
||||
changesOnly: false,
|
||||
debounce: 0,
|
||||
retention: 31536000,
|
||||
storageType: false
|
||||
}
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
objects.setObject('sql.0.testValue2', {
|
||||
common: {
|
||||
type: 'number',
|
||||
role: 'state'
|
||||
},
|
||||
type: 'state'
|
||||
},
|
||||
function () {
|
||||
sendTo('sql.0', 'enableHistory', {
|
||||
id: 'sql.0.testValue2',
|
||||
options: {
|
||||
changesOnly: true,
|
||||
debounce: 0,
|
||||
retention: 31536000,
|
||||
maxLength: 3,
|
||||
changesMinDelta: 0.5,
|
||||
aliasId: 'sql.0.testValue2-alias'
|
||||
}
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
// wait till adapter receives the new settings
|
||||
setTimeout(function () {
|
||||
done();
|
||||
}, 2000);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}, 10000);
|
||||
});
|
||||
});
|
||||
});
|
||||
it('Test ' + adapterShortName + ': Check Enabled Points after Enable', function (done) {
|
||||
this.timeout(20000);
|
||||
|
||||
sendTo('sql.0', 'getEnabledDPs', {}, function (result) {
|
||||
console.log(JSON.stringify(result));
|
||||
expect(Object.keys(result).length).to.be.equal(5);
|
||||
expect(result['sql.0.memRss'].enabled).to.be.true;
|
||||
setTimeout(function () {
|
||||
done();
|
||||
}, 15000);
|
||||
});
|
||||
});
|
||||
it('Test MySQL-with-dash: Write values into DB', function (done) {
|
||||
this.timeout(10000);
|
||||
|
||||
states.setState('sql.0.memRss', {val: 2, ts: now - 20000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: true, ts: now - 10000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: 2, ts: now - 5000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: 2.2, ts: now - 4000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: '2.5', ts: now - 3000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: 3, ts: now - 1000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: 'Test', ts: now - 500}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.testValue2', {val: 1, ts: now - 2000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.testValue2', {val: 3, ts: now - 1000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(done, 5000);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
it('Test MySQL-with-dash: Read values from DB using query', function (done) {
|
||||
this.timeout(10000);
|
||||
|
||||
sendTo('sql.0', 'query', 'SELECT id FROM `io-broker`.datapoints WHERE name="sql.0.memRss"', function (result) {
|
||||
console.log('MySQL-with-dash: ' + JSON.stringify(result.result, null, 2));
|
||||
sendTo('sql.0', 'query', 'SELECT * FROM `io-broker`.ts_number WHERE id=' + result.result[0].id, function (result) {
|
||||
console.log('MySQL-with-dash: ' + JSON.stringify(result.result, null, 2));
|
||||
expect(result.result.length).to.be.at.least(5);
|
||||
var found = 0;
|
||||
for (var i = 0; i < result.result.length; i++) {
|
||||
if (result.result[i].val >= 1 && result.result[i].val <= 3) found ++;
|
||||
}
|
||||
expect(found).to.be.equal(6);
|
||||
|
||||
setTimeout(function () {
|
||||
done();
|
||||
}, 3000);
|
||||
});
|
||||
});
|
||||
});
|
||||
it('Test MySQL-with-dash: Read values from DB using GetHistory', function (done) {
|
||||
this.timeout(10000);
|
||||
|
||||
sendTo('sql.0', 'getHistory', {
|
||||
id: 'sql.0.memRss',
|
||||
options: {
|
||||
start: now - 30000,
|
||||
limit: 50,
|
||||
count: 50,
|
||||
aggregate: 'none'
|
||||
}
|
||||
}, function (result) {
|
||||
console.log('MySQL-with-dash: ' + JSON.stringify(result.result, null, 2));
|
||||
expect(result.result.length).to.be.at.least(5);
|
||||
var found = 0;
|
||||
for (var i = 0; i < result.result.length; i++) {
|
||||
if (result.result[i].val >= 1 && result.result[i].val <= 3) found ++;
|
||||
}
|
||||
expect(found).to.be.equal(6);
|
||||
|
||||
sendTo('sql.0', 'getHistory', {
|
||||
id: 'sql.0.memRss',
|
||||
options: {
|
||||
start: now - 15000,
|
||||
end: now,
|
||||
limit: 2,
|
||||
count: 2,
|
||||
aggregate: 'none'
|
||||
}
|
||||
}, function (result) {
|
||||
console.log('MySQL-with-dash: ' + JSON.stringify(result.result, null, 2));
|
||||
expect(result.result.length).to.be.equal(2);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
it('Test ' + adapterShortName + ': Check Datapoint Types', function (done) {
|
||||
this.timeout(5000);
|
||||
|
||||
sendTo('sql.0', 'query', "SELECT name, type FROM `io-broker`.datapoints", function (result) {
|
||||
console.log('MySQL: ' + JSON.stringify(result.result, null, 2));
|
||||
expect(result.result.length).to.least(3);
|
||||
for (var i = 0; i < result.result.length; i++) {
|
||||
if (result.result[i].name === 'sql.0.memRss') {
|
||||
expect(result.result[i].type).to.be.equal(0);
|
||||
}
|
||||
else if (result.result[i].name === 'system.adapter.sql.0.memHeapTotal') {
|
||||
expect(result.result[i].type).to.be.equal(0);
|
||||
}
|
||||
else if (result.result[i].name === 'system.adapter.sql.0.alive') {
|
||||
expect(result.result[i].type).to.be.equal(2);
|
||||
}
|
||||
else if (result.result[i].name === 'system.adapter.sql.0.uptime') {
|
||||
expect(result.result[i].type).to.be.equal(0);
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
done();
|
||||
}, 3000);
|
||||
});
|
||||
});
|
||||
|
||||
it('Test ' + adapterShortName + ': Read values from DB using GetHistory for aliased testValue2', function (done) {
|
||||
this.timeout(25000);
|
||||
|
||||
sendTo('sql.0', 'getHistory', {
|
||||
id: 'sql.0.testValue2',
|
||||
options: {
|
||||
start: now - 5000,
|
||||
end: now,
|
||||
count: 50,
|
||||
aggregate: 'none'
|
||||
}
|
||||
}, function (result) {
|
||||
console.log(JSON.stringify(result.result, null, 2));
|
||||
expect(result.result.length).to.be.equal(2);
|
||||
|
||||
sendTo('sql.0', 'getHistory', {
|
||||
id: 'sql.0.testValue2-alias',
|
||||
options: {
|
||||
start: now - 5000,
|
||||
end: now,
|
||||
count: 50,
|
||||
aggregate: 'none'
|
||||
}
|
||||
}, function (result2) {
|
||||
console.log(JSON.stringify(result2.result, null, 2));
|
||||
expect(result2.result.length).to.be.equal(2);
|
||||
for (var i = 0; i < result2.result.length; i++) {
|
||||
expect(result2.result[i].val).to.be.equal(result.result[i].val);
|
||||
}
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Test ' + adapterShortName + ': Remove Alias-ID', function (done) {
|
||||
this.timeout(5000);
|
||||
|
||||
sendTo('sql.0', 'enableHistory', {
|
||||
id: 'sql.0.testValue2',
|
||||
options: {
|
||||
aliasId: ''
|
||||
}
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
// wait till adapter receives the new settings
|
||||
setTimeout(function () {
|
||||
done();
|
||||
}, 2000);
|
||||
});
|
||||
});
|
||||
it('Test ' + adapterShortName + ': Add Alias-ID again', function (done) {
|
||||
this.timeout(5000);
|
||||
|
||||
sendTo('sql.0', 'enableHistory', {
|
||||
id: 'sql.0.testValue2',
|
||||
options: {
|
||||
aliasId: 'this.is.a.test-value'
|
||||
}
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
// wait till adapter receives the new settings
|
||||
setTimeout(function () {
|
||||
done();
|
||||
}, 2000);
|
||||
});
|
||||
});
|
||||
it('Test ' + adapterShortName + ': Change Alias-ID', function (done) {
|
||||
this.timeout(5000);
|
||||
|
||||
sendTo('sql.0', 'enableHistory', {
|
||||
id: 'sql.0.testValue2',
|
||||
options: {
|
||||
aliasId: 'this.is.another.test-value'
|
||||
}
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
// wait till adapter receives the new settings
|
||||
setTimeout(function () {
|
||||
done();
|
||||
}, 2000);
|
||||
});
|
||||
});
|
||||
|
||||
it('Test ' + adapterShortName + ': Disable Datapoint again', function (done) {
|
||||
this.timeout(5000);
|
||||
|
||||
sendTo('sql.0', 'disableHistory', {
|
||||
id: 'sql.0.memRss',
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
setTimeout(done, 2000);
|
||||
});
|
||||
});
|
||||
it('Test ' + adapterShortName + ': Check Enabled Points after Disable', function (done) {
|
||||
this.timeout(5000);
|
||||
|
||||
sendTo('sql.0', 'getEnabledDPs', {}, function (result) {
|
||||
console.log(JSON.stringify(result));
|
||||
expect(Object.keys(result).length).to.be.equal(4);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
after('Test MySQL-with-dash: Stop js-controller', function (done) {
|
||||
this.timeout(6000);
|
||||
|
||||
setup.stopController(function (normalTerminated) {
|
||||
console.log('MySQL-with-dash: Adapter normal terminated: ' + normalTerminated);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
368
test/testMySQLExisting.js
Normal file
368
test/testMySQLExisting.js
Normal file
@@ -0,0 +1,368 @@
|
||||
/* jshint -W097 */// jshint strict:false
|
||||
/*jslint node: true */
|
||||
/*jshint expr: true*/
|
||||
var expect = require('chai').expect;
|
||||
var setup = require(__dirname + '/lib/setup');
|
||||
|
||||
var objects = null;
|
||||
var states = null;
|
||||
var onStateChanged = null;
|
||||
var onObjectChanged = null;
|
||||
var sendToID = 1;
|
||||
|
||||
var adapterShortName = setup.adapterName.substring(setup.adapterName.indexOf('.')+1);
|
||||
|
||||
var now = new Date().getTime();
|
||||
var now2;
|
||||
if (!now2) now2 = new Date().getTime();
|
||||
|
||||
function checkConnectionOfAdapter(cb, counter) {
|
||||
counter = counter || 0;
|
||||
if (counter > 20) {
|
||||
cb && cb('Cannot check connection');
|
||||
return;
|
||||
}
|
||||
|
||||
states.getState('system.adapter.' + adapterShortName + '.0.alive', function (err, state) {
|
||||
if (err) console.error('MySQL: ' + err);
|
||||
if (state && state.val) {
|
||||
cb && cb();
|
||||
} else {
|
||||
setTimeout(function () {
|
||||
checkConnectionOfAdapter(cb, counter + 1);
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function checkValueOfState(id, value, cb, counter) {
|
||||
counter = counter || 0;
|
||||
if (counter > 20) {
|
||||
cb && cb('Cannot check value Of State ' + id);
|
||||
return;
|
||||
}
|
||||
|
||||
states.getState(id, function (err, state) {
|
||||
if (err) console.error('MySQL: ' + err);
|
||||
if (value === null && !state) {
|
||||
cb && cb();
|
||||
} else
|
||||
if (state && (value === undefined || state.val === value)) {
|
||||
cb && cb();
|
||||
} else {
|
||||
setTimeout(function () {
|
||||
checkValueOfState(id, value, cb, counter + 1);
|
||||
}, 500);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function sendTo(target, command, message, callback) {
|
||||
onStateChanged = function (id, state) {
|
||||
if (id === 'messagebox.system.adapter.test.0') {
|
||||
callback(state.message);
|
||||
}
|
||||
};
|
||||
|
||||
states.pushMessage('system.adapter.' + target, {
|
||||
command: command,
|
||||
message: message,
|
||||
from: 'system.adapter.test.0',
|
||||
callback: {
|
||||
message: message,
|
||||
id: sendToID++,
|
||||
ack: false,
|
||||
time: (new Date()).getTime()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
describe('Test MySQL Existing', function() {
|
||||
before('Test MySQL Existing: Start js-controller', function (_done) {
|
||||
this.timeout(600000); // because of first install from npm
|
||||
setup.adapterStarted = false;
|
||||
|
||||
setup.setupController(function () {
|
||||
var config = setup.getAdapterConfig();
|
||||
// enable adapter
|
||||
config.common.enabled = true;
|
||||
config.common.loglevel = 'debug';
|
||||
|
||||
config.native.dbtype = 'mysql';
|
||||
config.native.user = 'root';
|
||||
if (process.env.APPVEYOR && process.env.APPVEYOR==='True') {
|
||||
config.native.password = 'Password12!';
|
||||
}
|
||||
|
||||
setup.setAdapterConfig(config.common, config.native);
|
||||
|
||||
setup.startController(true, function(id, obj) {}, function (id, state) {
|
||||
if (onStateChanged) onStateChanged(id, state);
|
||||
},
|
||||
function (_objects, _states) {
|
||||
objects = _objects;
|
||||
states = _states;
|
||||
_done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Test MySQL Existing: Check if adapter started', function (done) {
|
||||
this.timeout(60000);
|
||||
checkConnectionOfAdapter(function () {
|
||||
now = new Date().getTime();
|
||||
objects.setObject('system.adapter.test.0', {
|
||||
common: {
|
||||
|
||||
},
|
||||
type: 'instance'
|
||||
},
|
||||
function () {
|
||||
states.subscribeMessage('system.adapter.test.0');
|
||||
setTimeout(function() {
|
||||
sendTo('sql.0', 'enableHistory', {
|
||||
id: 'sql.0.memRss',
|
||||
options: {
|
||||
changesOnly: true,
|
||||
debounce: 0,
|
||||
retention: 31536000,
|
||||
changesMinDelta: 0.5,
|
||||
storageType: false
|
||||
}
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
sendTo('sql.0', 'enableHistory', {
|
||||
id: 'system.adapter.sql.0.memHeapTotal',
|
||||
options: {
|
||||
changesOnly: false,
|
||||
debounce: 0,
|
||||
retention: 31536000,
|
||||
storageType: 'Number'
|
||||
}
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
sendTo('sql.0', 'enableHistory', {
|
||||
id: 'system.adapter.sql.0.alive',
|
||||
options: {
|
||||
changesOnly: false,
|
||||
debounce: 0,
|
||||
retention: 31536000,
|
||||
storageType: false
|
||||
}
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
sendTo('sql.0', 'enableHistory', {
|
||||
id: 'system.adapter.sql.0.uptime',
|
||||
options: {
|
||||
changesOnly: false,
|
||||
debounce: 0,
|
||||
retention: 31536000,
|
||||
storageType: false
|
||||
}
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
// wait till adapter receives the new settings
|
||||
setTimeout(function () {
|
||||
done();
|
||||
}, 20000);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}, 10000);
|
||||
});
|
||||
});
|
||||
});
|
||||
it('Test ' + adapterShortName + ': Check Enabled Points after Enable', function (done) {
|
||||
this.timeout(20000);
|
||||
|
||||
sendTo('sql.0', 'getEnabledDPs', {}, function (result) {
|
||||
console.log(JSON.stringify(result));
|
||||
expect(Object.keys(result).length).to.be.equal(4);
|
||||
expect(result['sql.0.memRss'].enabled).to.be.true;
|
||||
setTimeout(function () {
|
||||
done();
|
||||
}, 15000);
|
||||
});
|
||||
});
|
||||
it('Test MySQL Existing: Write values into DB', function (done) {
|
||||
this.timeout(10000);
|
||||
|
||||
states.setState('sql.0.memRss', {val: 2, ts: now - 20000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: true, ts: now - 10000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: 2, ts: now - 5000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: 2.2, ts: now - 4000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: 2.3, ts: now - 3500}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: '2.5', ts: now - 3000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: 3, ts: now - 1000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: 'Test', ts: now - 500}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(done, 5000);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
it('Test MySQL Existing: Read values from DB using query', function (done) {
|
||||
this.timeout(10000);
|
||||
|
||||
sendTo('sql.0', 'query', 'SELECT id FROM yunkong2.datapoints WHERE name="sql.0.memRss"', function (result) {
|
||||
console.log('MySQL: ' + JSON.stringify(result.result, null, 2));
|
||||
sendTo('sql.0', 'query', 'SELECT * FROM yunkong2.ts_number WHERE id=' + result.result[0].id, function (result) {
|
||||
console.log('MySQL: ' + JSON.stringify(result.result, null, 2));
|
||||
expect(result.result.length).to.be.at.least(5);
|
||||
var found = 0;
|
||||
var found22 = false;
|
||||
var found23 = false;
|
||||
for (var i = 0; i < result.result.length; i++) {
|
||||
if (result.result[i].val >= 1 && result.result[i].val <= 3) found ++;
|
||||
if (result.result[i].val === 2.2) found22 = true;
|
||||
if (result.result[i].val === 2.3) found23 = true;
|
||||
}
|
||||
expect(found).to.be.equal(12);
|
||||
expect(found22).to.be.false;
|
||||
expect(found23).to.be.true;
|
||||
|
||||
setTimeout(function () {
|
||||
done();
|
||||
}, 3000);
|
||||
});
|
||||
});
|
||||
});
|
||||
it('Test MySQL Existing: Read values from DB using GetHistory', function (done) {
|
||||
this.timeout(10000);
|
||||
|
||||
sendTo('sql.0', 'getHistory', {
|
||||
id: 'sql.0.memRss',
|
||||
options: {
|
||||
start: now2 - 30000,
|
||||
limit: 50,
|
||||
count: 50,
|
||||
aggregate: 'none'
|
||||
}
|
||||
}, function (result) {
|
||||
console.log('MySQL: ' + JSON.stringify(result.result, null, 2));
|
||||
expect(result.result.length).to.be.at.least(5);
|
||||
var found = 0;
|
||||
for (var i = 0; i < result.result.length; i++) {
|
||||
if (result.result[i].val >= 1 && result.result[i].val <= 3) found ++;
|
||||
}
|
||||
expect(found).to.be.equal(12);
|
||||
|
||||
sendTo('sql.0', 'getHistory', {
|
||||
id: 'sql.0.memRss',
|
||||
options: {
|
||||
start: now2 - 15000,
|
||||
end: now,
|
||||
limit: 2,
|
||||
count: 2,
|
||||
aggregate: 'none'
|
||||
}
|
||||
}, function (result) {
|
||||
console.log('MySQL: ' + JSON.stringify(result.result, null, 2));
|
||||
expect(result.result.length).to.be.equal(2);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
it('Test ' + adapterShortName + ': Check Datapoint Types', function (done) {
|
||||
this.timeout(5000);
|
||||
|
||||
sendTo('sql.0', 'query', "SELECT name, type FROM yunkong2.datapoints", function (result) {
|
||||
console.log('MySQL: ' + JSON.stringify(result.result, null, 2));
|
||||
expect(result.result.length).to.least(3);
|
||||
for (var i = 0; i < result.result.length; i++) {
|
||||
if (result.result[i].name === 'sql.0.memRss') {
|
||||
expect(result.result[i].type).to.be.equal(0);
|
||||
}
|
||||
else if (result.result[i].name === 'system.adapter.sql.0.memHeapTotal') {
|
||||
expect(result.result[i].type).to.be.equal(0);
|
||||
}
|
||||
else if (result.result[i].name === 'system.adapter.sql.0.alive') {
|
||||
expect(result.result[i].type).to.be.equal(2);
|
||||
}
|
||||
else if (result.result[i].name === 'system.adapter.sql.0.uptime') {
|
||||
expect(result.result[i].type).to.be.equal(0);
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
done();
|
||||
}, 3000);
|
||||
});
|
||||
});
|
||||
it('Test ' + adapterShortName + ': Disable Datapoint again', function (done) {
|
||||
this.timeout(5000);
|
||||
|
||||
sendTo('sql.0', 'disableHistory', {
|
||||
id: 'sql.0.memRss',
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
setTimeout(done, 2000);
|
||||
});
|
||||
});
|
||||
it('Test ' + adapterShortName + ': Check Enabled Points after Disable', function (done) {
|
||||
this.timeout(5000);
|
||||
|
||||
sendTo('sql.0', 'getEnabledDPs', {}, function (result) {
|
||||
console.log(JSON.stringify(result));
|
||||
expect(Object.keys(result).length).to.be.equal(3);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
after('Test MySQL Existing: Stop js-controller', function (done) {
|
||||
this.timeout(6000);
|
||||
|
||||
setup.stopController(function (normalTerminated) {
|
||||
console.log('MySQL: Adapter normal terminated: ' + normalTerminated);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
369
test/testMySQLExistingNoNulls.js
Normal file
369
test/testMySQLExistingNoNulls.js
Normal file
@@ -0,0 +1,369 @@
|
||||
/* jshint -W097 */// jshint strict:false
|
||||
/*jslint node: true */
|
||||
/*jshint expr: true*/
|
||||
var expect = require('chai').expect;
|
||||
var setup = require(__dirname + '/lib/setup');
|
||||
|
||||
var objects = null;
|
||||
var states = null;
|
||||
var onStateChanged = null;
|
||||
var onObjectChanged = null;
|
||||
var sendToID = 1;
|
||||
|
||||
var adapterShortName = setup.adapterName.substring(setup.adapterName.indexOf('.')+1);
|
||||
|
||||
var now = new Date().getTime();
|
||||
var now2;
|
||||
if (!now2) now2 = new Date().getTime();
|
||||
|
||||
function checkConnectionOfAdapter(cb, counter) {
|
||||
counter = counter || 0;
|
||||
if (counter > 20) {
|
||||
cb && cb('Cannot check connection');
|
||||
return;
|
||||
}
|
||||
|
||||
states.getState('system.adapter.' + adapterShortName + '.0.alive', function (err, state) {
|
||||
if (err) console.error('MySQL: ' + err);
|
||||
if (state && state.val) {
|
||||
cb && cb();
|
||||
} else {
|
||||
setTimeout(function () {
|
||||
checkConnectionOfAdapter(cb, counter + 1);
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function checkValueOfState(id, value, cb, counter) {
|
||||
counter = counter || 0;
|
||||
if (counter > 20) {
|
||||
cb && cb('Cannot check value Of State ' + id);
|
||||
return;
|
||||
}
|
||||
|
||||
states.getState(id, function (err, state) {
|
||||
if (err) console.error('MySQL: ' + err);
|
||||
if (value === null && !state) {
|
||||
cb && cb();
|
||||
} else
|
||||
if (state && (value === undefined || state.val === value)) {
|
||||
cb && cb();
|
||||
} else {
|
||||
setTimeout(function () {
|
||||
checkValueOfState(id, value, cb, counter + 1);
|
||||
}, 500);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function sendTo(target, command, message, callback) {
|
||||
onStateChanged = function (id, state) {
|
||||
if (id === 'messagebox.system.adapter.test.0') {
|
||||
callback(state.message);
|
||||
}
|
||||
};
|
||||
|
||||
states.pushMessage('system.adapter.' + target, {
|
||||
command: command,
|
||||
message: message,
|
||||
from: 'system.adapter.test.0',
|
||||
callback: {
|
||||
message: message,
|
||||
id: sendToID++,
|
||||
ack: false,
|
||||
time: (new Date()).getTime()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
describe('Test MySQL Existing No Nulls', function() {
|
||||
before('Test MySQL Existing No Nulls: Start js-controller', function (_done) {
|
||||
this.timeout(600000); // because of first install from npm
|
||||
setup.adapterStarted = false;
|
||||
|
||||
setup.setupController(function () {
|
||||
var config = setup.getAdapterConfig();
|
||||
// enable adapter
|
||||
config.common.enabled = true;
|
||||
config.common.loglevel = 'debug';
|
||||
|
||||
config.native.writeNulls = false;
|
||||
config.native.dbtype = 'mysql';
|
||||
config.native.user = 'root';
|
||||
if (process.env.APPVEYOR && process.env.APPVEYOR==='True') {
|
||||
config.native.password = 'Password12!';
|
||||
}
|
||||
|
||||
setup.setAdapterConfig(config.common, config.native);
|
||||
|
||||
setup.startController(true, function(id, obj) {}, function (id, state) {
|
||||
if (onStateChanged) onStateChanged(id, state);
|
||||
},
|
||||
function (_objects, _states) {
|
||||
objects = _objects;
|
||||
states = _states;
|
||||
_done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Test MySQL Existing No Nulls: Check if adapter started', function (done) {
|
||||
this.timeout(60000);
|
||||
checkConnectionOfAdapter(function () {
|
||||
now = new Date().getTime();
|
||||
objects.setObject('system.adapter.test.0', {
|
||||
common: {
|
||||
|
||||
},
|
||||
type: 'instance'
|
||||
},
|
||||
function () {
|
||||
states.subscribeMessage('system.adapter.test.0');
|
||||
setTimeout(function() {
|
||||
sendTo('sql.0', 'enableHistory', {
|
||||
id: 'sql.0.memRss',
|
||||
options: {
|
||||
changesOnly: true,
|
||||
debounce: 0,
|
||||
retention: 31536000,
|
||||
changesMinDelta: 0.5,
|
||||
storageType: false
|
||||
}
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
sendTo('sql.0', 'enableHistory', {
|
||||
id: 'system.adapter.sql.0.memHeapTotal',
|
||||
options: {
|
||||
changesOnly: false,
|
||||
debounce: 0,
|
||||
retention: 31536000,
|
||||
storageType: 'Number'
|
||||
}
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
sendTo('sql.0', 'enableHistory', {
|
||||
id: 'system.adapter.sql.0.alive',
|
||||
options: {
|
||||
changesOnly: false,
|
||||
debounce: 0,
|
||||
retention: 31536000,
|
||||
storageType: false
|
||||
}
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
sendTo('sql.0', 'enableHistory', {
|
||||
id: 'system.adapter.sql.0.uptime',
|
||||
options: {
|
||||
changesOnly: false,
|
||||
debounce: 0,
|
||||
retention: 31536000,
|
||||
storageType: false
|
||||
}
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
// wait till adapter receives the new settings
|
||||
setTimeout(function () {
|
||||
done();
|
||||
}, 20000);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}, 10000);
|
||||
});
|
||||
});
|
||||
});
|
||||
it('Test ' + adapterShortName + ': Check Enabled Points after Enable', function (done) {
|
||||
this.timeout(20000);
|
||||
|
||||
sendTo('sql.0', 'getEnabledDPs', {}, function (result) {
|
||||
console.log(JSON.stringify(result));
|
||||
expect(Object.keys(result).length).to.be.equal(4);
|
||||
expect(result['sql.0.memRss'].enabled).to.be.true;
|
||||
setTimeout(function () {
|
||||
done();
|
||||
}, 15000);
|
||||
});
|
||||
});
|
||||
it('Test MySQL Existing No Nulls: Write values into DB', function (done) {
|
||||
this.timeout(10000);
|
||||
|
||||
states.setState('sql.0.memRss', {val: 2, ts: now - 20000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: true, ts: now - 10000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: 2, ts: now - 5000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: 2.2, ts: now - 4000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: 2.3, ts: now - 3500}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: '2.5', ts: now - 3000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: 3, ts: now - 1000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: 'Test', ts: now - 500}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(done, 5000);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
it('Test MySQL Existing No Nulls: Read values from DB using query', function (done) {
|
||||
this.timeout(10000);
|
||||
|
||||
sendTo('sql.0', 'query', 'SELECT id FROM yunkong2.datapoints WHERE name="sql.0.memRss"', function (result) {
|
||||
console.log('MySQL: ' + JSON.stringify(result.result, null, 2));
|
||||
sendTo('sql.0', 'query', 'SELECT * FROM yunkong2.ts_number WHERE id=' + result.result[0].id, function (result) {
|
||||
console.log('MySQL: ' + JSON.stringify(result.result, null, 2));
|
||||
expect(result.result.length).to.be.at.least(5);
|
||||
var found = 0;
|
||||
var found22 = false;
|
||||
var found23 = false;
|
||||
for (var i = 0; i < result.result.length; i++) {
|
||||
if (result.result[i].val >= 1 && result.result[i].val <= 3) found ++;
|
||||
if (result.result[i].val === 2.2) found22 = true;
|
||||
if (result.result[i].val === 2.3) found23 = true;
|
||||
}
|
||||
expect(found).to.be.equal(18);
|
||||
expect(found22).to.be.false;
|
||||
expect(found23).to.be.true;
|
||||
|
||||
setTimeout(function () {
|
||||
done();
|
||||
}, 3000);
|
||||
});
|
||||
});
|
||||
});
|
||||
it('Test MySQL Existing No Nulls: Read values from DB using GetHistory', function (done) {
|
||||
this.timeout(10000);
|
||||
|
||||
sendTo('sql.0', 'getHistory', {
|
||||
id: 'sql.0.memRss',
|
||||
options: {
|
||||
start: now2 - 30000,
|
||||
limit: 50,
|
||||
count: 50,
|
||||
aggregate: 'none'
|
||||
}
|
||||
}, function (result) {
|
||||
console.log('MySQL: ' + JSON.stringify(result.result, null, 2));
|
||||
expect(result.result.length).to.be.at.least(5);
|
||||
var found = 0;
|
||||
for (var i = 0; i < result.result.length; i++) {
|
||||
if (result.result[i].val >= 1 && result.result[i].val <= 3) found ++;
|
||||
}
|
||||
expect(found).to.be.equal(18);
|
||||
|
||||
sendTo('sql.0', 'getHistory', {
|
||||
id: 'sql.0.memRss',
|
||||
options: {
|
||||
start: now2 - 15000,
|
||||
end: now,
|
||||
limit: 2,
|
||||
count: 2,
|
||||
aggregate: 'none'
|
||||
}
|
||||
}, function (result) {
|
||||
console.log('MySQL: ' + JSON.stringify(result.result, null, 2));
|
||||
expect(result.result.length).to.be.equal(2);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
it('Test ' + adapterShortName + ': Check Datapoint Types', function (done) {
|
||||
this.timeout(5000);
|
||||
|
||||
sendTo('sql.0', 'query', "SELECT name, type FROM yunkong2.datapoints", function (result) {
|
||||
console.log('MySQL: ' + JSON.stringify(result.result, null, 2));
|
||||
expect(result.result.length).to.least(3);
|
||||
for (var i = 0; i < result.result.length; i++) {
|
||||
if (result.result[i].name === 'sql.0.memRss') {
|
||||
expect(result.result[i].type).to.be.equal(0);
|
||||
}
|
||||
else if (result.result[i].name === 'system.adapter.sql.0.memHeapTotal') {
|
||||
expect(result.result[i].type).to.be.equal(0);
|
||||
}
|
||||
else if (result.result[i].name === 'system.adapter.sql.0.alive') {
|
||||
expect(result.result[i].type).to.be.equal(2);
|
||||
}
|
||||
else if (result.result[i].name === 'system.adapter.sql.0.uptime') {
|
||||
expect(result.result[i].type).to.be.equal(0);
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
done();
|
||||
}, 3000);
|
||||
});
|
||||
});
|
||||
it('Test ' + adapterShortName + ': Disable Datapoint again', function (done) {
|
||||
this.timeout(5000);
|
||||
|
||||
sendTo('sql.0', 'disableHistory', {
|
||||
id: 'sql.0.memRss',
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
setTimeout(done, 2000);
|
||||
});
|
||||
});
|
||||
it('Test ' + adapterShortName + ': Check Enabled Points after Disable', function (done) {
|
||||
this.timeout(5000);
|
||||
|
||||
sendTo('sql.0', 'getEnabledDPs', {}, function (result) {
|
||||
console.log(JSON.stringify(result));
|
||||
expect(Object.keys(result).length).to.be.equal(3);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
after('Test MySQL Existing No Nulls: Stop js-controller', function (done) {
|
||||
this.timeout(6000);
|
||||
|
||||
setup.stopController(function (normalTerminated) {
|
||||
console.log('MySQL: Adapter normal terminated: ' + normalTerminated);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
91
test/testPackageFiles.js
Normal file
91
test/testPackageFiles.js
Normal file
@@ -0,0 +1,91 @@
|
||||
/* jshint -W097 */
|
||||
/* jshint strict:false */
|
||||
/* jslint node: true */
|
||||
/* jshint expr: true */
|
||||
var expect = require('chai').expect;
|
||||
var fs = require('fs');
|
||||
|
||||
describe('Test package.json and io-package.json', function() {
|
||||
it('Test package files', function (done) {
|
||||
console.log();
|
||||
|
||||
var fileContentIOPackage = fs.readFileSync(__dirname + '/../io-package.json', 'utf8');
|
||||
var ioPackage = JSON.parse(fileContentIOPackage);
|
||||
|
||||
var fileContentNPMPackage = fs.readFileSync(__dirname + '/../package.json', 'utf8');
|
||||
var npmPackage = JSON.parse(fileContentNPMPackage);
|
||||
|
||||
expect(ioPackage).to.be.an('object');
|
||||
expect(npmPackage).to.be.an('object');
|
||||
|
||||
expect(ioPackage.common.version, 'ERROR: Version number in io-package.json needs to exist').to.exist;
|
||||
expect(npmPackage.version, 'ERROR: Version number in package.json needs to exist').to.exist;
|
||||
|
||||
expect(ioPackage.common.version, 'ERROR: Version numbers in package.json and io-package.json needs to match').to.be.equal(npmPackage.version);
|
||||
|
||||
if (!ioPackage.common.news || !ioPackage.common.news[ioPackage.common.version]) {
|
||||
console.log('WARNING: No news entry for current version exists in io-package.json, no rollback in Admin possible!');
|
||||
console.log();
|
||||
}
|
||||
|
||||
expect(npmPackage.author, 'ERROR: Author in package.json needs to exist').to.exist;
|
||||
expect(ioPackage.common.authors, 'ERROR: Authors in io-package.json needs to exist').to.exist;
|
||||
|
||||
if (ioPackage.common.name.indexOf('template') !== 0) {
|
||||
if (Array.isArray(ioPackage.common.authors)) {
|
||||
expect(ioPackage.common.authors.length, 'ERROR: Author in io-package.json needs to be set').to.not.be.equal(0);
|
||||
if (ioPackage.common.authors.length === 1) {
|
||||
expect(ioPackage.common.authors[0], 'ERROR: Author in io-package.json needs to be a real name').to.not.be.equal('my Name <my@email.com>');
|
||||
}
|
||||
}
|
||||
else {
|
||||
expect(ioPackage.common.authors, 'ERROR: Author in io-package.json needs to be a real name').to.not.be.equal('my Name <my@email.com>');
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.log('WARNING: Testing for set authors field in io-package skipped because template adapter');
|
||||
console.log();
|
||||
}
|
||||
expect(fs.existsSync(__dirname + '/../README.md'), 'ERROR: README.md needs to exist! Please create one with description, detail information and changelog. English is mandatory.').to.be.true;
|
||||
if (!ioPackage.common.titleLang || typeof ioPackage.common.titleLang !== 'object') {
|
||||
console.log('WARNING: titleLang is not existing in io-package.json. Please add');
|
||||
console.log();
|
||||
}
|
||||
if (
|
||||
ioPackage.common.title.indexOf('yunkong2') !== -1 ||
|
||||
ioPackage.common.title.indexOf('yunkong2') !== -1 ||
|
||||
ioPackage.common.title.indexOf('adapter') !== -1 ||
|
||||
ioPackage.common.title.indexOf('Adapter') !== -1
|
||||
) {
|
||||
console.log('WARNING: title contains Adapter or yunkong2. It is clear anyway, that it is adapter for yunkong2.');
|
||||
console.log();
|
||||
}
|
||||
|
||||
if (ioPackage.common.name.indexOf('vis-') !== 0) {
|
||||
if (!ioPackage.common.materialize || !fs.existsSync(__dirname + '/../admin/index_m.html') || !fs.existsSync(__dirname + '/../gulpfile.js')) {
|
||||
console.log('WARNING: Admin3 support is missing! Please add it');
|
||||
console.log();
|
||||
}
|
||||
if (ioPackage.common.materialize) {
|
||||
expect(fs.existsSync(__dirname + '/../admin/index_m.html'), 'Admin3 support is enabled in io-package.json, but index_m.html is missing!').to.be.true;
|
||||
}
|
||||
}
|
||||
|
||||
var licenseFileExists = fs.existsSync(__dirname + '/../LICENSE');
|
||||
var fileContentReadme = fs.readFileSync(__dirname + '/../README.md', 'utf8');
|
||||
if (fileContentReadme.indexOf('## Changelog') === -1) {
|
||||
console.log('Warning: The README.md should have a section ## Changelog');
|
||||
console.log();
|
||||
}
|
||||
expect((licenseFileExists || fileContentReadme.indexOf('## License') !== -1), 'A LICENSE must exist as LICENSE file or as part of the README.md').to.be.true;
|
||||
if (!licenseFileExists) {
|
||||
console.log('Warning: The License should also exist as LICENSE file');
|
||||
console.log();
|
||||
}
|
||||
if (fileContentReadme.indexOf('## License') === -1) {
|
||||
console.log('Warning: The README.md should also have a section ## License to be shown in Admin3');
|
||||
console.log();
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
342
test/testPostgreSQL.js
Normal file
342
test/testPostgreSQL.js
Normal file
@@ -0,0 +1,342 @@
|
||||
/* jshint -W097 */// jshint strict:false
|
||||
/*jslint node: true */
|
||||
/*jshint expr: true*/
|
||||
var expect = require('chai').expect;
|
||||
var setup = require(__dirname + '/lib/setup');
|
||||
|
||||
var objects = null;
|
||||
var states = null;
|
||||
var onStateChanged = null;
|
||||
var onObjectChanged = null;
|
||||
var sendToID = 1;
|
||||
|
||||
var adapterShortName = setup.adapterName.substring(setup.adapterName.indexOf('.')+1);
|
||||
|
||||
var now = new Date().getTime();
|
||||
|
||||
function checkConnectionOfAdapter(cb, counter) {
|
||||
counter = counter || 0;
|
||||
if (counter > 20) {
|
||||
cb && cb('Cannot check connection');
|
||||
return;
|
||||
}
|
||||
|
||||
states.getState('system.adapter.' + adapterShortName + '.0.alive', function (err, state) {
|
||||
if (err) console.error('PostgreSQL: ' + err);
|
||||
if (state && state.val) {
|
||||
cb && cb();
|
||||
} else {
|
||||
setTimeout(function () {
|
||||
checkConnectionOfAdapter(cb, counter + 1);
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function checkValueOfState(id, value, cb, counter) {
|
||||
counter = counter || 0;
|
||||
if (counter > 20) {
|
||||
cb && cb('Cannot check value Of State ' + id);
|
||||
return;
|
||||
}
|
||||
|
||||
states.getState(id, function (err, state) {
|
||||
if (err) console.error('PostgreSQL: ' + err);
|
||||
if (value === null && !state) {
|
||||
cb && cb();
|
||||
} else
|
||||
if (state && (value === undefined || state.val === value)) {
|
||||
cb && cb();
|
||||
} else {
|
||||
setTimeout(function () {
|
||||
checkValueOfState(id, value, cb, counter + 1);
|
||||
}, 500);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function sendTo(target, command, message, callback) {
|
||||
onStateChanged = function (id, state) {
|
||||
if (id === 'messagebox.system.adapter.test.0') {
|
||||
callback(state.message);
|
||||
}
|
||||
};
|
||||
|
||||
states.pushMessage('system.adapter.' + target, {
|
||||
command: command,
|
||||
message: message,
|
||||
from: 'system.adapter.test.0',
|
||||
callback: {
|
||||
message: message,
|
||||
id: sendToID++,
|
||||
ack: false,
|
||||
time: (new Date()).getTime()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
describe('Test PostgreSQL', function() {
|
||||
before('Test PostgreSQL: Start js-controller', function (_done) {
|
||||
this.timeout(600000); // because of first install from npm
|
||||
setup.adapterStarted = false;
|
||||
|
||||
setup.setupController(function () {
|
||||
var config = setup.getAdapterConfig();
|
||||
// enable adapter
|
||||
config.common.enabled = true;
|
||||
config.common.loglevel = 'debug';
|
||||
|
||||
config.native.dbtype = 'postgresql';
|
||||
config.native.user = 'postgres';
|
||||
if (process.env.APPVEYOR && process.env.APPVEYOR==='True') {
|
||||
config.native.password = 'Password12!';
|
||||
}
|
||||
|
||||
setup.setAdapterConfig(config.common, config.native);
|
||||
|
||||
setup.startController(true, function(id, obj) {}, function (id, state) {
|
||||
if (onStateChanged) onStateChanged(id, state);
|
||||
},
|
||||
function (_objects, _states) {
|
||||
objects = _objects;
|
||||
states = _states;
|
||||
objects.setObject('sql.0.memRss', {
|
||||
common: {
|
||||
type: 'number',
|
||||
role: 'state',
|
||||
custom: {
|
||||
"sql.0": {
|
||||
enabled: true,
|
||||
changesOnly: true,
|
||||
debounce: 0,
|
||||
retention: 31536000,
|
||||
maxLength: 3,
|
||||
changesMinDelta: 0.5
|
||||
}
|
||||
}
|
||||
},
|
||||
type: 'state'
|
||||
}, _done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Test PostgreSQL: Check if adapter started', function (done) {
|
||||
this.timeout(60000);
|
||||
checkConnectionOfAdapter(function () {
|
||||
now = new Date().getTime();
|
||||
objects.setObject('system.adapter.test.0', {
|
||||
common: {
|
||||
|
||||
},
|
||||
type: 'instance'
|
||||
},
|
||||
function () {
|
||||
states.subscribeMessage('system.adapter.test.0');
|
||||
setTimeout(function () {
|
||||
sendTo('sql.0', 'enableHistory', {
|
||||
id: 'system.adapter.sql.0.memHeapTotal',
|
||||
options: {
|
||||
changesOnly: false,
|
||||
debounce: 0,
|
||||
retention: 31536000,
|
||||
storageType: 'String'
|
||||
}
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
sendTo('sql.0', 'enableHistory', {
|
||||
id: 'system.adapter.sql.0.uptime',
|
||||
options: {
|
||||
changesOnly: false,
|
||||
debounce: 0,
|
||||
retention: 31536000,
|
||||
storageType: 'Boolean'
|
||||
}
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
// wait till adapter receives the new settings
|
||||
setTimeout(function () {
|
||||
done();
|
||||
}, 20000);
|
||||
});
|
||||
});
|
||||
}, 10000);
|
||||
});
|
||||
});
|
||||
});
|
||||
it('Test ' + adapterShortName + ': Check Enabled Points after Enable', function (done) {
|
||||
this.timeout(20000);
|
||||
|
||||
sendTo('sql.0', 'getEnabledDPs', {}, function (result) {
|
||||
console.log(JSON.stringify(result));
|
||||
expect(Object.keys(result).length).to.be.equal(3);
|
||||
expect(result['sql.0.memRss'].enabled).to.be.true;
|
||||
setTimeout(function () {
|
||||
done();
|
||||
}, 15000);
|
||||
});
|
||||
});
|
||||
it('Test PostgreSQL: Write values into DB', function (done) {
|
||||
this.timeout(10000);
|
||||
|
||||
this.timeout(10000);
|
||||
|
||||
states.setState('sql.0.memRss', {val: 2, ts: now - 20000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: true, ts: now - 10000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: 2, ts: now - 5000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: 2.2, ts: now - 4000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: '2.5', ts: now - 3000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: 3, ts: now - 1000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: 'Test', ts: now - 500}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(done, 5000);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
it('Test PostgreSQL: Read values from DB using query', function (done) {
|
||||
this.timeout(10000);
|
||||
|
||||
sendTo('sql.0', 'query', "SELECT id FROM datapoints WHERE name='sql.0.memRss'", function (result) {
|
||||
sendTo('sql.0', 'query', 'SELECT * FROM ts_number WHERE id=' + result.result[0].id, function (result) {
|
||||
console.log('PostgreSQL: ' + JSON.stringify(result.result, null, 2));
|
||||
expect(result.result.length).to.be.at.least(5);
|
||||
var found = 0;
|
||||
for (var i = 0; i < result.result.length; i++) {
|
||||
if (result.result[i].val >= 1 && result.result[i].val <= 3) found ++;
|
||||
}
|
||||
expect(found).to.be.equal(6);
|
||||
|
||||
setTimeout(function () {
|
||||
done();
|
||||
}, 3000);
|
||||
});
|
||||
});
|
||||
});
|
||||
it('Test PostgreSQL: Read values from DB using GetHistory', function (done) {
|
||||
this.timeout(10000);
|
||||
|
||||
sendTo('sql.0', 'getHistory', {
|
||||
id: 'sql.0.memRss',
|
||||
options: {
|
||||
start: now - 30000,
|
||||
limit: 50,
|
||||
count: 50,
|
||||
aggregate: 'none'
|
||||
}
|
||||
}, function (result) {
|
||||
console.log('PostgreSQL: ' + JSON.stringify(result.result, null, 2));
|
||||
expect(result.result.length).to.be.at.least(5);
|
||||
var found = 0;
|
||||
for (var i = 0; i < result.result.length; i++) {
|
||||
if (result.result[i].val >= 1 && result.result[i].val <= 3) found ++;
|
||||
}
|
||||
expect(found).to.be.equal(6);
|
||||
|
||||
sendTo('sql.0', 'getHistory', {
|
||||
id: 'sql.0.memRss',
|
||||
options: {
|
||||
start: now - 15000,
|
||||
end: now,
|
||||
limit: 2,
|
||||
count: 2,
|
||||
aggregate: 'none'
|
||||
}
|
||||
}, function (result) {
|
||||
console.log('PostgreSQL: ' + JSON.stringify(result.result, null, 2));
|
||||
expect(result.result.length).to.be.equal(2);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
it('Test ' + adapterShortName + ': Check Datapoint Types', function (done) {
|
||||
this.timeout(5000);
|
||||
|
||||
sendTo('sql.0', 'query', "SELECT name, type FROM datapoints", function (result) {
|
||||
console.log('PostgreSQL: ' + JSON.stringify(result.result, null, 2));
|
||||
expect(result.result.length).to.least(3);
|
||||
for (var i = 0; i < result.result.length; i++) {
|
||||
if (result.result[i].name === 'sql.0.memRss') {
|
||||
expect(result.result[i].type).to.be.equal(0);
|
||||
}
|
||||
else if (result.result[i].name === 'system.adapter.sql.0.memHeapTotal') {
|
||||
expect(result.result[i].type).to.be.equal(1);
|
||||
}
|
||||
else if (result.result[i].name === 'system.adapter.sql.0.uptime') {
|
||||
expect(result.result[i].type).to.be.equal(2);
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
done();
|
||||
}, 3000);
|
||||
});
|
||||
});
|
||||
it('Test ' + adapterShortName + ': Disable Datapoint again', function (done) {
|
||||
this.timeout(5000);
|
||||
|
||||
sendTo('sql.0', 'disableHistory', {
|
||||
id: 'sql.0.memRss',
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
setTimeout(done, 2000);
|
||||
});
|
||||
});
|
||||
it('Test ' + adapterShortName + ': Check Enabled Points after Disable', function (done) {
|
||||
this.timeout(5000);
|
||||
|
||||
sendTo('sql.0', 'getEnabledDPs', {}, function (result) {
|
||||
console.log(JSON.stringify(result));
|
||||
expect(Object.keys(result).length).to.be.equal(2);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
after('Test PostgreSQL: Stop js-controller', function (done) {
|
||||
this.timeout(6000);
|
||||
|
||||
setup.stopController(function (normalTerminated) {
|
||||
console.log('PostgreSQL: Adapter normal terminated: ' + normalTerminated);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
355
test/testSQLite.js
Normal file
355
test/testSQLite.js
Normal file
@@ -0,0 +1,355 @@
|
||||
/* jshint -W097 */// jshint strict:false
|
||||
/*jslint node: true */
|
||||
/*jshint expr: true*/
|
||||
var expect = require('chai').expect;
|
||||
var setup = require(__dirname + '/lib/setup');
|
||||
|
||||
var objects = null;
|
||||
var states = null;
|
||||
var onStateChanged = null;
|
||||
var onObjectChanged = null;
|
||||
var sendToID = 1;
|
||||
|
||||
var adapterShortName = setup.adapterName.substring(setup.adapterName.indexOf('.')+1);
|
||||
|
||||
var now = new Date().getTime();
|
||||
|
||||
function checkConnectionOfAdapter(cb, counter) {
|
||||
counter = counter || 0;
|
||||
if (counter > 20) {
|
||||
cb && cb('Cannot check connection');
|
||||
return;
|
||||
}
|
||||
|
||||
states.getState('system.adapter.' + adapterShortName + '.0.alive', function (err, state) {
|
||||
if (err) console.error('SQLite:' + err);
|
||||
if (state && state.val) {
|
||||
cb && cb();
|
||||
} else {
|
||||
setTimeout(function () {
|
||||
checkConnectionOfAdapter(cb, counter + 1);
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function checkValueOfState(id, value, cb, counter) {
|
||||
counter = counter || 0;
|
||||
if (counter > 20) {
|
||||
cb && cb('Cannot check value Of State ' + id);
|
||||
return;
|
||||
}
|
||||
|
||||
states.getState(id, function (err, state) {
|
||||
if (err) console.error('SQLite:' + err);
|
||||
if (value === null && !state) {
|
||||
cb && cb();
|
||||
} else
|
||||
if (state && (value === undefined || state.val === value)) {
|
||||
cb && cb();
|
||||
} else {
|
||||
setTimeout(function () {
|
||||
checkValueOfState(id, value, cb, counter + 1);
|
||||
}, 500);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function sendTo(target, command, message, callback) {
|
||||
onStateChanged = function (id, state) {
|
||||
if (id === 'messagebox.system.adapter.test.0') {
|
||||
callback(state.message);
|
||||
}
|
||||
};
|
||||
|
||||
states.pushMessage('system.adapter.' + target, {
|
||||
command: command,
|
||||
message: message,
|
||||
from: 'system.adapter.test.0',
|
||||
callback: {
|
||||
message: message,
|
||||
id: sendToID++,
|
||||
ack: false,
|
||||
time: (new Date()).getTime()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
describe('Test SQLite', function() {
|
||||
before('Test SQLite: Start js-controller', function (_done) {
|
||||
this.timeout(600000); // because of first install from npm
|
||||
setup.adapterStarted = false;
|
||||
|
||||
setup.setupController(function () {
|
||||
var config = setup.getAdapterConfig();
|
||||
// enable adapter
|
||||
config.common.enabled = true;
|
||||
config.common.loglevel = 'debug';
|
||||
|
||||
config.native.dbtype = 'sqlite';
|
||||
|
||||
setup.setAdapterConfig(config.common, config.native);
|
||||
|
||||
setup.startController(true, function(id, obj) {}, function (id, state) {
|
||||
if (onStateChanged) onStateChanged(id, state);
|
||||
},
|
||||
function (_objects, _states) {
|
||||
objects = _objects;
|
||||
states = _states;
|
||||
objects.setObject('sql.0.memRss', {
|
||||
common: {
|
||||
type: 'number',
|
||||
role: 'state',
|
||||
custom: {
|
||||
"sql.0": {
|
||||
enabled: true,
|
||||
changesOnly: true,
|
||||
debounce: 0,
|
||||
retention: 31536000,
|
||||
maxLength: 3,
|
||||
changesMinDelta: 0.5
|
||||
}
|
||||
}
|
||||
},
|
||||
type: 'state'
|
||||
}, _done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Test SQLite: Check if adapter started', function (done) {
|
||||
this.timeout(60000);
|
||||
checkConnectionOfAdapter(function () {
|
||||
now = new Date().getTime();
|
||||
objects.setObject('system.adapter.test.0', {
|
||||
common: {
|
||||
|
||||
},
|
||||
type: 'instance'
|
||||
},
|
||||
function () {
|
||||
states.subscribeMessage('system.adapter.test.0');
|
||||
setTimeout(function () {
|
||||
sendTo('sql.0', 'enableHistory', {
|
||||
id: 'system.adapter.sql.0.memHeapTotal',
|
||||
options: {
|
||||
changesOnly: false,
|
||||
debounce: 0,
|
||||
retention: 31536000,
|
||||
storageType: 'String'
|
||||
}
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
sendTo('sql.0', 'enableHistory', {
|
||||
id: 'system.adapter.sql.0.alive',
|
||||
options: {
|
||||
changesOnly: false,
|
||||
debounce: 0,
|
||||
retention: 31536000,
|
||||
storageType: 'Boolean'
|
||||
}
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
sendTo('sql.0', 'enableHistory', {
|
||||
id: 'system.adapter.sql.0.uptime',
|
||||
options: {
|
||||
changesOnly: false,
|
||||
debounce: 0,
|
||||
retention: 31536000,
|
||||
storageType: false
|
||||
}
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
// wait till adapter receives the new settings
|
||||
setTimeout(function () {
|
||||
done();
|
||||
}, 20000);
|
||||
});
|
||||
});
|
||||
});
|
||||
}, 10000);
|
||||
});
|
||||
});
|
||||
});
|
||||
it('Test ' + adapterShortName + ': Check Enabled Points after Enable', function (done) {
|
||||
this.timeout(20000);
|
||||
|
||||
sendTo('sql.0', 'getEnabledDPs', {}, function (result) {
|
||||
console.log(JSON.stringify(result));
|
||||
expect(Object.keys(result).length).to.be.equal(4);
|
||||
expect(result['sql.0.memRss'].enabled).to.be.true;
|
||||
setTimeout(function () {
|
||||
done();
|
||||
}, 15000);
|
||||
});
|
||||
});
|
||||
it('Test SQLite: Write values into DB', function (done) {
|
||||
this.timeout(10000);
|
||||
|
||||
this.timeout(10000);
|
||||
|
||||
states.setState('sql.0.memRss', {val: 2, ts: now - 20000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: true, ts: now - 10000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: 2, ts: now - 5000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: 2.2, ts: now - 4000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: '2.5', ts: now - 3000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: 3, ts: now - 1000}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(function () {
|
||||
states.setState('sql.0.memRss', {val: 'Test', ts: now - 500}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(done, 5000);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
it('Test SQLite: Read values from DB using query', function (done) {
|
||||
this.timeout(10000);
|
||||
|
||||
sendTo('sql.0', 'query', 'SELECT id FROM datapoints WHERE name="sql.0.memRss"', function (result) {
|
||||
sendTo('sql.0', 'query', 'SELECT * FROM ts_number WHERE id=' + result.result[0].id, function (result) {
|
||||
console.log('SQLite:' + JSON.stringify(result.result, null, 2));
|
||||
expect(result.result.length).to.be.at.least(5);
|
||||
var found = 0;
|
||||
for (var i = 0; i < result.result.length; i++) {
|
||||
if (result.result[i].val >= 1 && result.result[i].val <= 3) found ++;
|
||||
}
|
||||
expect(found).to.be.equal(6);
|
||||
|
||||
setTimeout(function () {
|
||||
done();
|
||||
}, 3000);
|
||||
});
|
||||
});
|
||||
});
|
||||
it('Test SQLite: Read values from DB using GetHistory', function (done) {
|
||||
this.timeout(20000);
|
||||
|
||||
sendTo('sql.0', 'getHistory', {
|
||||
id: 'sql.0.memRss',
|
||||
options: {
|
||||
start: now - 30000,
|
||||
limit: 50,
|
||||
count: 50,
|
||||
aggregate: 'none'
|
||||
}
|
||||
}, function (result) {
|
||||
console.log('SQLite:' + JSON.stringify(result.result, null, 2));
|
||||
expect(result.result.length).to.be.at.least(5);
|
||||
var found = 0;
|
||||
for (var i = 0; i < result.result.length; i++) {
|
||||
if (result.result[i].val >= 1 && result.result[i].val <= 3) found ++;
|
||||
}
|
||||
expect(found).to.be.equal(6);
|
||||
|
||||
sendTo('sql.0', 'getHistory', {
|
||||
id: 'sql.0.memRss',
|
||||
options: {
|
||||
start: now - 15000,
|
||||
end: now,
|
||||
limit: 2,
|
||||
count: 2,
|
||||
aggregate: 'none'
|
||||
}
|
||||
}, function (result) {
|
||||
console.log('SQLite:' + JSON.stringify(result.result, null, 2));
|
||||
expect(result.result.length).to.be.equal(2);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
it('Test ' + adapterShortName + ': Check Datapoint Types', function (done) {
|
||||
this.timeout(125000);
|
||||
|
||||
setTimeout(function() {
|
||||
sendTo('sql.0', 'query', "SELECT name, type FROM datapoints", function (result) {
|
||||
console.log('SQLite: ' + JSON.stringify(result.result, null, 2));
|
||||
expect(result.result.length).to.least(3);
|
||||
for (var i = 0; i < result.result.length; i++) {
|
||||
if (result.result[i].name === 'sql.0.memRss') {
|
||||
expect(result.result[i].type).to.be.equal(0);
|
||||
}
|
||||
else if (result.result[i].name === 'system.adapter.sql.0.memHeapTotal') {
|
||||
expect(result.result[i].type).to.be.equal(1);
|
||||
}
|
||||
else if (result.result[i].name === 'system.adapter.sql.0.uptime') {
|
||||
expect(result.result[i].type).to.be.equal(0);
|
||||
}
|
||||
else if (result.result[i].name === 'system.adapter.sql.0.alive') {
|
||||
expect(result.result[i].type).to.be.equal(2);
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
done();
|
||||
}, 3000);
|
||||
});
|
||||
}, 121000);
|
||||
});
|
||||
it('Test ' + adapterShortName + ': Disable Datapoint again', function (done) {
|
||||
this.timeout(5000);
|
||||
|
||||
sendTo('sql.0', 'disableHistory', {
|
||||
id: 'sql.0.memRss',
|
||||
}, function (result) {
|
||||
expect(result.error).to.be.undefined;
|
||||
expect(result.success).to.be.true;
|
||||
setTimeout(done, 2000);
|
||||
});
|
||||
});
|
||||
it('Test ' + adapterShortName + ': Check Enabled Points after Disable', function (done) {
|
||||
this.timeout(5000);
|
||||
|
||||
sendTo('sql.0', 'getEnabledDPs', {}, function (result) {
|
||||
console.log(JSON.stringify(result));
|
||||
expect(Object.keys(result).length).to.be.equal(3);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
after('Test SQLite: Stop js-controller', function (done) {
|
||||
this.timeout(6000);
|
||||
|
||||
setup.stopController(function (normalTerminated) {
|
||||
console.log('SQLite: Adapter normal terminated: ' + normalTerminated);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user