@mschaeffler/node-red-hourmeter 0.2.5 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -3
- package/hourmeter.html +38 -4
- package/hourmeter.js +42 -25
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -29,7 +29,7 @@ The counter is started / stopped according to the value of the payload:
|
|
|
29
29
|
||on|started|
|
|
30
30
|
||start|started|
|
|
31
31
|
|
|
32
|
-
A [local filesystem context store](https://nodered.org/docs/user-guide/context#saving-context-data-to-the-file-system)
|
|
32
|
+
A [local filesystem context store](https://nodered.org/docs/user-guide/context#saving-context-data-to-the-file-system) is needed to store the internal data.
|
|
33
33
|
|
|
34
34
|
### Input
|
|
35
35
|
|
|
@@ -37,7 +37,7 @@ A [local filesystem context store](https://nodered.org/docs/user-guide/context#s
|
|
|
37
37
|
|:-------|:-------|:----------------------------------|
|
|
38
38
|
|payload | | Starts or stopps the counting. |
|
|
39
39
|
|reset |boolean |If true, resets the counter to 0.|
|
|
40
|
-
|
|
|
40
|
+
|query |boolean |If true, just querries the state of the counter.|
|
|
41
41
|
|
|
42
42
|
### Outputs
|
|
43
43
|
|
|
@@ -45,13 +45,15 @@ A [local filesystem context store](https://nodered.org/docs/user-guide/context#s
|
|
|
45
45
|
|
|
46
46
|
|msg. | type | description |
|
|
47
47
|
|:-------|:-------|:----------------------------------|
|
|
48
|
-
|payload | boolean
|
|
48
|
+
|payload | boolean| Is counting active?|
|
|
49
|
+
|reason | string | Reason of the message output.|
|
|
49
50
|
|
|
50
51
|
#### hour counter
|
|
51
52
|
|
|
52
53
|
|msg. | type | description |
|
|
53
54
|
|:-------|:-------|:----------------------------------|
|
|
54
55
|
|payload | number | Value of the hour counter.|
|
|
56
|
+
|reason | string | Reason of the message output.|
|
|
55
57
|
|
|
56
58
|
### Parameters
|
|
57
59
|
|
|
@@ -59,6 +61,8 @@ A [local filesystem context store](https://nodered.org/docs/user-guide/context#s
|
|
|
59
61
|
|:-----|:-------|:----------------------------------|
|
|
60
62
|
|topic| string | Topic to send output values with.|
|
|
61
63
|
|cycle| number |Cyclic time of output; 0 is only at state change.|
|
|
64
|
+
|Contextstore|context store| context store for storing the values.|
|
|
65
|
+
|Status|boolean| the actual value as a node status.|
|
|
62
66
|
|
|
63
67
|
## Example Flow
|
|
64
68
|
|
package/hourmeter.html
CHANGED
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
defaults: {
|
|
6
6
|
name: {value:""},
|
|
7
7
|
topic:{value:""},
|
|
8
|
-
cycle:{value:"0", required:true, validate:RED.validators.number()}
|
|
8
|
+
cycle:{value:"0", required:true, validate:RED.validators.number()},
|
|
9
|
+
contextStore:{value:"",required:true},
|
|
10
|
+
showState:{value:false}
|
|
9
11
|
},
|
|
10
12
|
inputs:1,
|
|
11
13
|
outputs:2,
|
|
@@ -18,7 +20,23 @@
|
|
|
18
20
|
},
|
|
19
21
|
inputLabels: 'on/off message',
|
|
20
22
|
outputLabels: ['boolean value','hour counter'],
|
|
21
|
-
paletteLabel: "hour meter"
|
|
23
|
+
paletteLabel: "hour meter",
|
|
24
|
+
oneditprepare: function() {
|
|
25
|
+
const node = this
|
|
26
|
+
// populate store names
|
|
27
|
+
$("#node-input-contextStore").empty();
|
|
28
|
+
//$("#node-input-contextStore").append(`<option value="none">None</option>`);
|
|
29
|
+
const defaultStore = RED.settings.hasOwnProperty('context') ? RED.settings.context.default : ''
|
|
30
|
+
RED.settings.context.stores.forEach(function(item){
|
|
31
|
+
if( item ) {
|
|
32
|
+
const opt = $(`<option value="${item}">${item}${item===defaultStore?" (default)":""}</option>`);
|
|
33
|
+
$("#node-input-contextStore").append(opt);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
const currentStore = node.contextStore || '';
|
|
37
|
+
// select the current option
|
|
38
|
+
$("#node-input-contextStore").val(currentStore);
|
|
39
|
+
}
|
|
22
40
|
});
|
|
23
41
|
</script>
|
|
24
42
|
|
|
@@ -35,6 +53,14 @@
|
|
|
35
53
|
<label for="node-input-cycle"><i class="fa fa-hourglass-o"></i> Cycle [min]</label>
|
|
36
54
|
<input type="text" id="node-input-cycle">
|
|
37
55
|
</div>
|
|
56
|
+
<div class="form-row">
|
|
57
|
+
<label for="node-input-contextStore"><i class="fa fa-database"></i> Contextstore</label>
|
|
58
|
+
<select type="text" id="node-input-contextStore"></select>
|
|
59
|
+
</div>
|
|
60
|
+
<div class="form-row">
|
|
61
|
+
<label for="node-input-showStatus"><i class="fa fa-star-o"></i> Status</label>
|
|
62
|
+
<input type="checkbox" id="node-input-showState" style="display:inline-block; width:20px; vertical-align:baseline;">
|
|
63
|
+
</div>
|
|
38
64
|
</script>
|
|
39
65
|
|
|
40
66
|
<script type="text/html" data-help-name="hourmeter">
|
|
@@ -56,7 +82,7 @@
|
|
|
56
82
|
</table>
|
|
57
83
|
|
|
58
84
|
<p>A <a href="https://nodered.org/docs/user-guide/context#saving-context-data-to-the-file-system">local filesystem context store</a>
|
|
59
|
-
|
|
85
|
+
is needed to store the internal data.</p>
|
|
60
86
|
|
|
61
87
|
<h3>Input</h3>
|
|
62
88
|
<dl class="message-properties">
|
|
@@ -64,7 +90,7 @@
|
|
|
64
90
|
<dd> Starts or stopps the counting.</dd>
|
|
65
91
|
<dt>reset <span class="property-type">boolean</span></dt>
|
|
66
92
|
<dd> If true, resets the counter to 0.</dd>
|
|
67
|
-
<dt>
|
|
93
|
+
<dt>query <span class="property-type">boolean</span></dt>
|
|
68
94
|
<dd> If true, just querries the state of the counter.</dd>
|
|
69
95
|
</dl>
|
|
70
96
|
|
|
@@ -74,12 +100,16 @@
|
|
|
74
100
|
<dl class="message-properties">
|
|
75
101
|
<dt>payload <span class="property-type">boolean</span></dt>
|
|
76
102
|
<dd> Is counting active?</dd>
|
|
103
|
+
<dt>reason <span class="property-type">string</span></dt>
|
|
104
|
+
<dd> Reason of the message output.</dd>
|
|
77
105
|
</dl>
|
|
78
106
|
|
|
79
107
|
<h4>hour counter</h4>
|
|
80
108
|
<dl class="message-properties">
|
|
81
109
|
<dt>payload <span class="property-type">number</span></dt>
|
|
82
110
|
<dd> Value of the hour counter.</dd>
|
|
111
|
+
<dt>reason <span class="property-type">string</span></dt>
|
|
112
|
+
<dd> Reason of the message output.</dd>
|
|
83
113
|
</dl>
|
|
84
114
|
|
|
85
115
|
<h3>Parameters</h3>
|
|
@@ -88,6 +118,10 @@
|
|
|
88
118
|
<dd> Topic to send output values with.</dd>
|
|
89
119
|
<dt>cycle <span class="property-type">number</span></dt>
|
|
90
120
|
<dd> Cyclic time of output; 0 is only at state change.</dd>
|
|
121
|
+
<dt>Contextstore <span class="property-type">context store</span></dt>
|
|
122
|
+
<dd> context store for storing the values; <code>none</code> is no storage.</dd>
|
|
123
|
+
<dt>Status <span class="property-type">boolean</span></dt>
|
|
124
|
+
<dd> shows the actual value as a node status.</dd>
|
|
91
125
|
</dl>
|
|
92
126
|
|
|
93
127
|
</script>
|
package/hourmeter.js
CHANGED
|
@@ -4,34 +4,55 @@ module.exports = function(RED)
|
|
|
4
4
|
function HourMeterNode(config)
|
|
5
5
|
{
|
|
6
6
|
RED.nodes.createNode(this,config);
|
|
7
|
-
this.config
|
|
8
|
-
this.topic
|
|
9
|
-
this.cycle
|
|
10
|
-
this.
|
|
7
|
+
this.config = config;
|
|
8
|
+
this.topic = config.topic ?? "";
|
|
9
|
+
this.cycle = Number( config.cycle ?? 0 );
|
|
10
|
+
this.contextStore = config.contextStore ?? "none";
|
|
11
|
+
this.showState = Boolean( config.showState );
|
|
12
|
+
this.interval_id = null;
|
|
11
13
|
var node = this;
|
|
12
14
|
var context = this.context();
|
|
15
|
+
node.status( "" );
|
|
13
16
|
|
|
14
17
|
if( this.cycle > 0 )
|
|
15
18
|
{
|
|
16
|
-
|
|
19
|
+
function emitQuery()
|
|
17
20
|
{
|
|
18
|
-
node.emit( "input", {
|
|
19
|
-
}
|
|
21
|
+
node.emit( "input", {query:true} );
|
|
22
|
+
}
|
|
23
|
+
setTimeout( emitQuery, 75 );
|
|
24
|
+
this.interval_id = setInterval( emitQuery, this.cycle*60*1000 );
|
|
20
25
|
}
|
|
21
26
|
|
|
22
27
|
node.on( 'input', function(msg,send,done)
|
|
23
28
|
{
|
|
29
|
+
let data;
|
|
30
|
+
|
|
31
|
+
function sendOutput(reason)
|
|
32
|
+
{
|
|
33
|
+
const out = data.counter/3600;
|
|
34
|
+
if( node.showState )
|
|
35
|
+
{
|
|
36
|
+
node.status( `${data.state} / ${out.toFixed(1)}` );
|
|
37
|
+
}
|
|
38
|
+
send( [
|
|
39
|
+
{ topic:node.topic, payload:data.switchOn!==undefined, reason:reason },
|
|
40
|
+
{ topic:node.topic, payload:out, reason:reason }
|
|
41
|
+
] );
|
|
42
|
+
}
|
|
43
|
+
|
|
24
44
|
if( msg.reset )
|
|
25
45
|
{
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
46
|
+
data = { counter:0 }
|
|
47
|
+
context.set( "data", data, node.contextStore );
|
|
48
|
+
sendOutput( "reset" );
|
|
29
49
|
}
|
|
30
50
|
else
|
|
31
51
|
{
|
|
32
|
-
const now
|
|
33
|
-
|
|
34
|
-
|
|
52
|
+
const now = Date.now();
|
|
53
|
+
data = context.get( "data", node.contextStore ) ?? { counter:0 };
|
|
54
|
+
|
|
55
|
+
if( ( !msg.query ) && ( msg.payload !== undefined ) )
|
|
35
56
|
{
|
|
36
57
|
if( msg.payload !== data.state )
|
|
37
58
|
{
|
|
@@ -46,6 +67,7 @@ module.exports = function(RED)
|
|
|
46
67
|
if( data.switchOn === undefined )
|
|
47
68
|
{
|
|
48
69
|
data.switchOn = now;
|
|
70
|
+
sendOutput( "on" );
|
|
49
71
|
}
|
|
50
72
|
break;
|
|
51
73
|
case false:
|
|
@@ -59,12 +81,13 @@ module.exports = function(RED)
|
|
|
59
81
|
{
|
|
60
82
|
data.counter += (now - data.switchOn)/1000;
|
|
61
83
|
delete data.switchOn;
|
|
84
|
+
sendOutput( "off" );
|
|
62
85
|
}
|
|
63
86
|
break;
|
|
64
87
|
}
|
|
65
88
|
data.state = msg.payload;
|
|
89
|
+
context.set( "data", data, node.contextStore );
|
|
66
90
|
}
|
|
67
|
-
context.set( "data", data, "storeInFile" );
|
|
68
91
|
}
|
|
69
92
|
else
|
|
70
93
|
{
|
|
@@ -73,22 +96,16 @@ module.exports = function(RED)
|
|
|
73
96
|
data.counter += (now - data.switchOn)/1000;
|
|
74
97
|
data.switchOn = now;
|
|
75
98
|
}
|
|
99
|
+
sendOutput( "query" );
|
|
76
100
|
}
|
|
77
|
-
const out = data.counter/3600;
|
|
78
|
-
node.status( `${data.state} / ${out.toFixed(1)}` );
|
|
79
|
-
send( [ { topic:this.topic, payload:data.switchOn!==undefined }, { topic:this.topic, payload:out } ] );
|
|
80
101
|
}
|
|
81
102
|
done();
|
|
82
103
|
} );
|
|
104
|
+
|
|
105
|
+
node.on('close', function() {
|
|
106
|
+
clearInterval( node.interval_id );
|
|
107
|
+
});
|
|
83
108
|
}
|
|
84
109
|
|
|
85
110
|
RED.nodes.registerType("hourmeter",HourMeterNode);
|
|
86
|
-
|
|
87
|
-
HourMeterNode.prototype.close = function()
|
|
88
|
-
{
|
|
89
|
-
if( this.interval_id != null )
|
|
90
|
-
{
|
|
91
|
-
clearInterval( this.interval_id );
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
111
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mschaeffler/node-red-hourmeter",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "A working hour meter for NodeRed.",
|
|
5
5
|
"license": "LGPL-2.1",
|
|
6
6
|
"homepage": "https://github.com/m-schaeffler/node-red-my-nodes/tree/main/node-red-hourmeter",
|
|
@@ -9,13 +9,13 @@
|
|
|
9
9
|
"url": "git+https://github.com/m-schaeffler/node-red-my-nodes.git"
|
|
10
10
|
},
|
|
11
11
|
"engines": {
|
|
12
|
-
"node": ">=
|
|
12
|
+
"node": ">=18"
|
|
13
13
|
},
|
|
14
14
|
"keywords": [
|
|
15
15
|
"node-red"
|
|
16
16
|
],
|
|
17
17
|
"node-red": {
|
|
18
|
-
"version": ">=1.
|
|
18
|
+
"version": ">=3.1.0",
|
|
19
19
|
"nodes": {
|
|
20
20
|
"nop": "hourmeter.js"
|
|
21
21
|
}
|
|
@@ -23,5 +23,8 @@
|
|
|
23
23
|
"author": {
|
|
24
24
|
"name": "Mathias Schäffler",
|
|
25
25
|
"url": "https://github.com/m-schaeffler"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"test": "mocha \"test/*_spec.js\""
|
|
26
29
|
}
|
|
27
30
|
}
|