node-red-contrib-eskomsepush 0.0.8 → 0.0.10

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.
@@ -0,0 +1,33 @@
1
+ ---
2
+ name: Bug report
3
+ about: Create a report to help us improve
4
+ title: "[BUG]"
5
+ labels: ''
6
+ assignees: ''
7
+
8
+ ---
9
+
10
+ **Describe the bug**
11
+ A clear and concise description of what the bug is.
12
+
13
+ **To Reproduce**
14
+ Steps to reproduce the behavior:
15
+ 1. Using node '...'
16
+ 2. Click on '....'
17
+ 3. See error
18
+
19
+ **Expected behavior**
20
+ A clear and concise description of what you expected to happen.
21
+
22
+ **Screenshots**
23
+ If applicable, add screenshots to help explain your problem.
24
+
25
+ **Flow**
26
+ If applicable, add a flow to help explain your problem.
27
+
28
+ **Software (please complete the following information):**
29
+ - node-red-contrib-eskomsepush version:
30
+
31
+ **Additional context**
32
+ Add any other context about the problem here.
33
+
@@ -0,0 +1,21 @@
1
+ ---
2
+ name: Feature request
3
+ about: Suggest an idea for the EskomSePush node
4
+ title: "[Feature]"
5
+ labels: enhancement
6
+ assignees: ''
7
+
8
+ ---
9
+
10
+ **Is your feature request related to a problem? Please describe.**
11
+ A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12
+
13
+ **Describe the solution you'd like**
14
+ A clear and concise description of what you want to happen.
15
+
16
+ **Describe alternatives you've considered**
17
+ A clear and concise description of any alternative solutions or features you've considered.
18
+
19
+ **Additional context**
20
+ Add any other context or screenshots about the feature request here.
21
+
package/README.md CHANGED
@@ -20,7 +20,9 @@ The node has been made to work well together with the [@victronenergy/node-red-c
20
20
 
21
21
  You can find the example flow for this via importing the [victron-minsoc-stage-based.json](examples/victron-minsoc-stage-based.json) file.
22
22
 
23
- ### Configuration
23
+ ### Installation & Configuration
24
+
25
+ Install the node from within Node-RED from the menu: Manage pallete -> Install (tab) -> Search for "eskom" and click "install".
24
26
 
25
27
  First you will need a _licence key_. You can get one from [here](https://eskomsepush.gumroad.com/l/api), by subscribing to the Free model. Note that this is for personal use only.
26
28
 
@@ -106,6 +108,10 @@ The status will show the situation regarding the API calls and when the next
106
108
  shedding wil start or end. It also shows the count of API calls that have been
107
109
  done and how many are left. This updates every 10 minutes.
108
110
 
111
+ The red color status can be either filled (dot) or not (ring). In case of a dot,
112
+ the load schedding is because of an _event_. When it is a ring, it is caused by
113
+ a matching _schedule_.
114
+
109
115
  ### Documentation
110
116
 
111
117
  Documentation for the API can be found [here](https://documenter.getpostman.com/view/1296288/UzQuNk3E)
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-red-contrib-eskomsepush",
3
- "version": "0.0.8",
3
+ "version": "0.0.10",
4
4
  "description": "Node-RED interface for the Eskomsepush API",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -1,4 +1,33 @@
1
1
  <script type="text/javascript">
2
+ function checkForValidLicense() {
3
+ var licensekey = $('#node-input-licensekey').val();
4
+
5
+ var regexValidator = RED.validators.regex(/^[0-9A-F\-]{35}$/)
6
+ var isValid = regexValidator(licensekey)
7
+
8
+ if (isValid) {
9
+ document.getElementById("searchAreaText").disabled = false
10
+ $.ajax({
11
+ url: '/eskomsepush/api',
12
+ method: 'GET',
13
+ data: {
14
+ token: licensekey,
15
+ },
16
+ success: function(response) {
17
+ $('#api_info').text(response.allowance.count + '/' + response.allowance.limit)
18
+ if (response.allowance.count >= response.allowance.limit) {
19
+ document.getElementById("searchAreaText").disabled = true
20
+ }
21
+ },
22
+ error: function(error) {
23
+ node.warn(error)
24
+ }
25
+ })
26
+ } else {
27
+ document.getElementById("searchAreaText").disabled = true
28
+ }
29
+ }
30
+
2
31
  RED.nodes.registerType('eskomsepush',{
3
32
  category: 'network',
4
33
  color: '#ffffff',
@@ -7,7 +36,8 @@
7
36
  licensekey: {value:"", validate: RED.validators.regex(/^[0-9A-F\-]{35}$/)},
8
37
  area: {value:""},
9
38
  statusselect: {value:"", validate: RED.validators.regex(/^(eskom|capetown)$/)},
10
- test: { value: false }
39
+ test: { value: false },
40
+ verbose: {value: false}
11
41
  },
12
42
  inputs:0,
13
43
  outputs:2,
@@ -16,53 +46,48 @@
16
46
  return this.name||"EskomSePush API";
17
47
  },
18
48
  oneditprepare: function oneditprepare() {
49
+ checkForValidLicense()
19
50
 
20
- }
21
- });
22
-
23
- function searchArea() {
24
- var input = document.getElementById("node-input-area");
25
- var dropdown = document.getElementById("areaDropdown");
26
- var licensekey = document.getElementById("node-input-licensekey");
27
-
28
- if (!RED.validators.regex(licensekey.value, /^[0-9A-F\-]{35}$/)) {
29
- return
30
- }
31
-
32
- if (input.value.length >= 5) {
33
- dropdown.innerHTML = "";
51
+ $("button#searchAreaId").on("click", function() {
52
+ var licensekey = $("#node-input-licensekey").val()
53
+ var regexValidator = RED.validators.regex(/^[0-9A-F\-]{35}$/)
54
+ var isValid = regexValidator(licensekey)
55
+ var search = $("input#searchAreaText").val()
56
+ var arealist = ''
34
57
 
35
- $.ajax({
36
- url: '/eskomsepush/search',
37
- method: 'GET',
38
- data: {
39
- token: licensekey.value,
40
- search: input.value
41
- },
42
- success: function(response) {
43
- for (var i = 0; i < response.areas.length; i++) {
44
- var option = document.createElement("option");
45
- option.text = response.areas[i].name;
46
- option.value = response.areas[i].id;
47
- dropdown.add(option);
48
- }
49
- },
50
- error: function(error) {
51
- node.warn(error)
58
+ if (isValid && search != '') {
59
+ $.ajax({
60
+ url: '/eskomsepush/search',
61
+ method: 'GET',
62
+ data: {
63
+ token: licensekey,
64
+ search
65
+ },
66
+ success: function(response) {
67
+ for (var i = 0; i < response.areas.length; i++) {
68
+ arealist += '<li id="' + response.areas[i].id + '">' + response.areas[i].name +
69
+ ', '+ response.areas[i].region + '</li>'
70
+ }
71
+ $('#list-areas').html(arealist)
72
+ $('#list-areas li').on('click', function() {
73
+ $('#node-input-area').val($(this).attr("id"))
74
+ $('#node-input-name').val($(this).text().split(',')[0])
75
+ })
76
+ checkForValidLicense()
77
+ },
78
+ error: function(error) {
79
+ node.warn(error)
80
+ }
81
+ })
52
82
  }
53
83
  })
54
- dropdown.style.display = "block";
55
- dropdown.addEventListener("change", function() {
56
- input.value = dropdown.value;
57
- dropdown.style.display = "none";
84
+
85
+ $("#node-input-licensekey").on("input", function() {
86
+ checkForValidLicense()
58
87
  });
59
- input.addEventListener("focusout", function() {
60
- dropdown.style.display = "none"
61
- })
62
- } else {
63
- dropdown.style.display = "none";
64
88
  }
65
- }
89
+ });
90
+
66
91
  </script>
67
92
 
68
93
  <script type="text/html" data-template-name="eskomsepush">
@@ -75,13 +100,8 @@
75
100
  <input type="password" id="node-input-licensekey" placeholder="License key" required>
76
101
  </div>
77
102
  <div class="form-row">
78
- <label for="node-input-area"><i class="fa fa-tag"></i> Area</label>
79
- <input type="text" id="node-input-area" placeholder="Area" onkeyup="searchArea()">
80
- <select id="areaDropdown" style="display: none;"></select>
81
- </div>
82
- <div class="form-row">
83
- <label style="min-width:190px" for="node-input-test"><i class="fa fa-volume-up"></i> Use test data</label>
84
- <input type="checkbox" checked id="node-input-test" style="max-width:30px">
103
+ <label for="node-input-area"><i class="fa fa-tag"></i> Area id</label>
104
+ <input type="text" id="node-input-area" placeholder="Area id">
85
105
  </div>
86
106
  <div class="form-row">
87
107
  <label for="node-input-statusselect"><i class="fa fa-location-arrow"></i> Status select</label>
@@ -90,6 +110,31 @@
90
110
  <option value="capetown">Cape Town</option>
91
111
  </select>
92
112
  </div>
113
+ <div class="form-row">
114
+ <label style="min-width:190px" for="node-input-test"><i class="fa fa-volume-up"></i> Use test data</label>
115
+ <input type="checkbox" checked id="node-input-test" style="max-width:30px">
116
+ </div>
117
+ <div class="form-tips">
118
+ <p>In order to fill out the properties, you will need to add the correct license key, which can be
119
+ obtained <a href="https://eskomsepush.gumroad.com/l/api">here</a>. Apart from that, the
120
+ <em>Aread id</em> needs to be filled out. The search form below can help you to obtain that.<br />
121
+ Once you have a valid licence key filled out in the form, a query willl be done, checking
122
+ how many credits you have left. If you have credits left, the form
123
+ can be used to search for the needed area id. <strong>Each search will cost you 5 credits.</strong>
124
+ </p>
125
+
126
+ <ul id="list-areas"></ul>
127
+
128
+ <p>
129
+ Queries left: <span id="api_info">unknown/unknown</span><br />
130
+ <input type="text" id="searchAreaText" placeholder="Area" disabled />
131
+ <button id="searchAreaId">Search</button><br />
132
+ </p>
133
+ </div>
134
+ <div class="form-row" style="margin-bottom:0px;">
135
+ <input type="checkbox" checked id="node-input-verbose" style="display:inline-block; margin-left:8px; width:auto; vertical-align:top;">
136
+ <label style="min-width:390px" for="node-input-verbose"><i class="fa fa-power"></i> Verbose: add extra logging when running</label>
137
+ </div>
93
138
  </script>
94
139
 
95
140
  <script type="text/html" data-help-name="eskomsepush">
@@ -111,8 +156,7 @@ see how many queries you have left.</p>
111
156
  <h3 id="configuration">Configuration</h3>
112
157
 
113
158
  <p>First you will need a <em>licence key</em>. You can get one from <a href="https://eskomsepush.gumroad.com/l/api">here</a>, by subsribing to the Free model. Note that this is for personal use only.</p>
114
- <p>Next you need to insert the correct area. Once you entered 5 characters (and a valid license is used), the API will be used for searching the correct area. Do note that this will cost some of the daily queries. If you don&#39;t want that and you already know the id of the area, fill out the area first and then the license
115
- key.</p>
159
+ <p>Next you need to insert the correct area. Once a valid license is filled out, the API can be used for searching the correct area id. Do note that this will cost some of the daily queries. If you don&#39;t want that and you already know the id of the area, fill out the area id manually.</p>
116
160
  <p>Then you need to fill out which status to follow. This can be either <em>National</em> (eskom) or <em>Capetown</em>.</p>
117
161
  <p>If the <em>test</em> checkbox has been selected, test data for the area will be fetched instead of the actual schedule. This is useful when debugging.</p>
118
162
 
@@ -122,47 +166,53 @@ key.</p>
122
166
 
123
167
  <pre>
124
168
  {
125
- "payload":false,
126
- "LoadShedding":{
127
- "schedule":{
128
- "next":{
129
- "start":1683561600000,
130
- "end":1683570600000,
131
- "type":"schedule"
132
- },
133
- "active":false
134
- },
135
- "event":{
136
- "next":{
137
- "start":1683561600000,
138
- "end":1683570600000
139
- },
140
- "active":false
169
+ "payload": false,
170
+ "LoadShedding": {
171
+ "schedule": {
172
+ "next": {
173
+ "start": 1684267200000,
174
+ "end": 1684276200000,
175
+ "type": "schedule",
176
+ "duration": 9000,
177
+ "islong": false
178
+ },
179
+ "active": false
180
+ },
181
+ "event": {
182
+ "next": {
183
+ "start": 1684267200000,
184
+ "end": 1684276200000
185
+ },
186
+ "active": false
187
+ },
188
+ "checked": "15:38",
189
+ "next": {
190
+ "start": 1684267200000,
191
+ "end": 1684276200000,
192
+ "type": "schedule",
193
+ "duration": 9000,
194
+ "islong": false
195
+ },
196
+ "active": false
141
197
  },
142
- "checked":"13:35",
143
- "next":{
144
- "start":1683561600000,
145
- "end":1683570600000,
146
- "type":"schedule"
198
+ "stage": "3",
199
+ "statusselect": "capetown",
200
+ "api": {
201
+ "count": 45,
202
+ "limit": 50,
203
+ "lastStatusUpdate": "Tue May 16 2023 15:38:15 GMT+0200 (Central European Summer Time)",
204
+ "lastScheduleUpdate": "Tue May 16 2023 15:38:15 GMT+0200 (Central European Summer Time)"
147
205
  },
148
- "active":false
149
- },
150
- "stage":"5",
151
- "statusselect":"capetown",
152
- "api":{
153
- "count":12,
154
- "limit":50,
155
- "lastStatusUpdate":"Mon May 08 2023 13:34:30 GMT+0200 (Central European Summer Time)",
156
- "lastScheduleUpdate":"Mon May 08 2023 13:34:30 GMT+0200 (Central European Summer Time)"
157
- },
158
- "_msgid":"6e77b593b7f9eda4"
159
- }
206
+ "_msgid": "dfa429a93a16472d"
207
+ }
160
208
  </pre>
161
209
 
162
- <p>The <tt>start</tt> and <tt>end</tt> objects contain the time as unix timestamp in the Javascript format (milliseconds after the epoch).</p>
210
+ <p>The <tt>start</tt> and <tt>end</tt> objects contain the time as unix timestamp in the Javascript format (milliseconds after the epoch),
211
+ while the <tt>duration</tt> is in seconds. The <code>msg.LoadShedding.next.islong</code> value is boolean and will be <em>true</em> if the
212
+ shedding lasts 4 hours or longer.</p>
163
213
 
164
214
  <p>The second output shows <code>msg.stage</code> and <code>msg.schedule</code>, containing the latest information as retrieved from the API.
165
- This output is mainly useful when writing your own functions and logic.</p>
215
+ This output is mainly useful when debugging or writing your own functions and logic.</p>
166
216
 
167
217
  <h3 id="status">Status</h3>
168
218
 
@@ -170,9 +220,29 @@ This output is mainly useful when writing your own functions and logic.</p>
170
220
  It also shows the count of API calls that have been done and
171
221
  how many are left. This updates every 10 minutes.</p>
172
222
 
223
+ <p>
224
+ The yellow color status can be either filled (dot) or not (ring). In case of a dot,
225
+ the load schedding is because of an <em>event</em>. When it is a ring, it is caused by
226
+ a matching <em>schedule</em>.
227
+ </p>
228
+
229
+ <div id="legend">
230
+ <ul>
231
+ <li><svg class="bullet" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><rect x="5" y="5" width="9" height="9" rx="2" ry="2" stroke-width="3" fill="#fff" stroke="#5a8"></rect>
232
+ </svg> - grid available, working properly</li>
233
+ <li><svg class="bullet" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><rect x="5" y="5" width="9" height="9" rx="2" ry="2" stroke-width="3" fill="#F9DF31" stroke="#F9DF31"></rect>
234
+ </svg> - no grid, load shedding because of an <strong>event</strong></li>
235
+ <li><svg class="bullet" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><rect x="5" y="5" width="9" height="9" rx="2" ry="2" stroke-width="3" fill="#fff" stroke="#F9DF31"></rect>
236
+ </svg> - no grid, load shedding because of a <strong>schedule</strong></li>
237
+ <li><svg class="bullet" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><rect x="5" y="5" width="9" height="9" rx="2" ry="2" stroke-width="3" fill="#fff" stroke="#c00"></rect>
238
+ </svg> - ran out of API calls</li>
239
+ </ul>
240
+ </div>
241
+
173
242
  <h1 id="documentation">Documentation</h1>
174
- <p>Documentation for the API can be found <a href="https://documenter.getpostman.com/view/1296288/UzQuNk3E">here</a></p>
175
243
 
244
+ <p>The GitHub site for the node can be found <a href="https://github.com/dirkjanfaber/node-red-contrib-eskomsepush">here</a>, while the documentation for the API can be found <a href="https://documenter.getpostman.com/view/1296288/UzQuNk3E">here</a>.
245
+ For issues and/or suggestions for improving the node, please use the <a href="https://github.com/dirkjanfaber/node-red-contrib-eskomsepush/issues">issue tracker</a>.</p>
176
246
  </script>
177
247
 
178
248
  <style>
@@ -183,4 +253,24 @@ select#areaDropdown {
183
253
  position: absolute;
184
254
  left: 120px;
185
255
  }
256
+ #list-areas li {
257
+ cursor: pointer;
258
+ }
259
+
260
+ #legend ul {
261
+ list-style: none;
262
+ padding: 0;
263
+ }
264
+ #legend li {
265
+ margin-bottom: 10px;
266
+ position: relative;
267
+ padding-left: 25px;
268
+ }
269
+ .bullet {
270
+ position: absolute;
271
+ top: 2px;
272
+ left: 0;
273
+ width: 35px;
274
+ height: 35px;
275
+ }
186
276
  </style>
@@ -10,17 +10,20 @@ module.exports = function (RED) {
10
10
  let lastStageUpdate = new Date()
11
11
  let lastScheduleUpdate = new Date()
12
12
 
13
-
14
- function updateStatus(node) {
13
+ function updateStatus (node) {
15
14
  let fill = 'green'
16
15
  let shape = 'ring'
17
16
  let statusText = ''
17
+
18
+ if (node.config.verbose === true) {
19
+ node.warn('Running function updateStatus')
20
+ }
18
21
  if (Stage && Stage.status && Stage.status[node.config.statusselect].stage) {
19
- statusText += 'Stage '+Stage.status[node.config.statusselect].stage
22
+ statusText += 'Stage ' + (Stage.active || Stage.status[node.config.statusselect].stage)
20
23
  }
21
24
  if (LoadShedding && LoadShedding.active && LoadShedding.next && LoadShedding.next.end) {
22
25
  statusText += ' - ' + new Date(LoadShedding.next.end).toLocaleTimeString()
23
- fill = 'red'
26
+ fill = 'yellow'
24
27
  if (LoadShedding.type === 'event') {
25
28
  shape = 'dot'
26
29
  }
@@ -32,7 +35,7 @@ module.exports = function (RED) {
32
35
  if (EskomSePushAPI) {
33
36
  statusText += ` (API: ${EskomSePushAPI.allowance.count}/${EskomSePushAPI.allowance.limit})`
34
37
  if (EskomSePushAPI.allowance.count >= EskomSePushAPI.allowance.limit) {
35
- fill = 'red'
38
+ fill = 'red'
36
39
  }
37
40
  }
38
41
  node.status({
@@ -43,6 +46,10 @@ module.exports = function (RED) {
43
46
  function checkAllowance (node) {
44
47
  const options = {}
45
48
  const headers = { token: node.config.licensekey }
49
+
50
+ if (node.config.verbose === true) {
51
+ node.warn('Running function checkAllowance')
52
+ }
46
53
  axios.get('https://developer.sepush.co.za/business/2.0/api_allowance',
47
54
  { params: options, headers }).then(function (response) {
48
55
  EskomSePushAPI = response.data
@@ -56,6 +63,10 @@ module.exports = function (RED) {
56
63
  function checkStage (node) {
57
64
  const options = {}
58
65
  const headers = { token: node.config.licensekey }
66
+
67
+ if (node.config.verbose === true) {
68
+ node.warn('Running function checkStage')
69
+ }
59
70
  axios.get('https://developer.sepush.co.za/business/2.0/status',
60
71
  { params: options, headers }).then(function (response) {
61
72
  Stage = response.data
@@ -70,6 +81,10 @@ module.exports = function (RED) {
70
81
  const options = { id: node.config.area }
71
82
  const headers = { token: node.config.licensekey }
72
83
  const url = 'https://developer.sepush.co.za/business/2.0/area'
84
+
85
+ if (node.config.verbose === true) {
86
+ node.warn('Running function checkSchedule')
87
+ }
73
88
  if (node.config.test) {
74
89
  options.test = 'current'
75
90
  }
@@ -87,6 +102,9 @@ module.exports = function (RED) {
87
102
  function updateSheddingStatus (node) {
88
103
  const now = new Date()
89
104
 
105
+ if (node.config.verbose === true) {
106
+ node.warn('Running function updateSheddingStatus')
107
+ }
90
108
  if (EskomSePushAPI === null || (now.getTime() - lastStatusUpdate.getTime()) > 600000) {
91
109
  checkAllowance(node)
92
110
  lastStatusUpdate = now
@@ -112,7 +130,7 @@ module.exports = function (RED) {
112
130
  }
113
131
 
114
132
  if (Stage && Schedule && EskomSePushAPI) {
115
- const stage = Stage.status[node.config.statusselect].stage
133
+ let stage = Stage.status[node.config.statusselect].stage
116
134
  const nowtime = now.toLocaleTimeString('en-US', { hour12: false, hour: '2-digit', minute: '2-digit' })
117
135
  LoadShedding = {
118
136
  schedule: {
@@ -125,20 +143,40 @@ module.exports = function (RED) {
125
143
  },
126
144
  checked: nowtime
127
145
  }
128
- for (const schedule of Schedule.schedule.days[0].stages[stage - 1]) {
146
+
147
+ if (!Array.isArray(Schedule.schedule.days[0].stages[stage])) {
148
+ node.warn(`No schedule defined for stage ${stage}`)
149
+ return
150
+ }
151
+
152
+ for (const schedule of Schedule.schedule.days[0].stages[stage]) {
129
153
  if (nowtime >= schedule.split('-')[0] && nowtime <= schedule.split('-')[1]) {
130
154
  LoadShedding.schedule = {
131
155
  active: true
132
156
  }
133
- LoadShedding.schedule.next = {
134
- start: Date.parse(Schedule.schedule.days[0].date + ' ' + schedule.split('-')[0]),
135
- end: Date.parse(Schedule.schedule.days[0].date + ' ' + schedule.split('-')[1])
157
+ if (schedule.split('-')[0] < schedule.split('-')[1]) {
158
+ LoadShedding.schedule.next = {
159
+ start: Date.parse(Schedule.schedule.days[0].date + ' ' + schedule.split('-')[0]),
160
+ end: Date.parse(Schedule.schedule.days[0].date + ' ' + schedule.split('-')[1])
161
+ }
162
+ } else {
163
+ LoadShedding.schedule.next = {
164
+ start: Date.parse(Schedule.schedule.days[0].date + ' ' + schedule.split('-')[0]),
165
+ end: Date.parse(Schedule.schedule.days[1].date + ' ' + schedule.split('-')[1])
166
+ }
136
167
  }
137
168
  }
138
169
  if (nowtime < schedule.split('-')[0]) {
139
- LoadShedding.schedule.next = {
140
- start: Date.parse(Schedule.schedule.days[0].date + ' ' + schedule.split('-')[0]),
141
- end: Date.parse(Schedule.schedule.days[0].date + ' ' + schedule.split('-')[1])
170
+ if (schedule.split('-')[0] < schedule.split('-')[1]) {
171
+ LoadShedding.schedule.next = {
172
+ start: Date.parse(Schedule.schedule.days[0].date + ' ' + schedule.split('-')[0]),
173
+ end: Date.parse(Schedule.schedule.days[0].date + ' ' + schedule.split('-')[1])
174
+ }
175
+ } else {
176
+ LoadShedding.schedule.next = {
177
+ start: Date.parse(Schedule.schedule.days[0].date + ' ' + schedule.split('-')[0]),
178
+ end: Date.parse(Schedule.schedule.days[1].date + ' ' + schedule.split('-')[1])
179
+ }
142
180
  }
143
181
  }
144
182
  }
@@ -155,6 +193,12 @@ module.exports = function (RED) {
155
193
  }
156
194
  if (now >= LoadShedding.event.next.start && now < LoadShedding.event.next.end) {
157
195
  LoadShedding.event.active = true
196
+ if (Schedule.events[0].note.match(/Stage (\d+)/i)) {
197
+ stage = Schedule.events[0].note.match(/Stage (\d+)/i)[1]
198
+ Stage.active = stage
199
+ }
200
+ } else {
201
+ Stage.active = stage
158
202
  }
159
203
 
160
204
  if (!LoadShedding.schedule | !LoadShedding.schedule.next ||
@@ -172,6 +216,9 @@ module.exports = function (RED) {
172
216
  LoadShedding.next.type = 'event'
173
217
  }
174
218
 
219
+ LoadShedding.next.duration = (LoadShedding.next.end - LoadShedding.next.start) / 1000
220
+ LoadShedding.next.islong = LoadShedding.next.duration >= (4 * 3600)
221
+
175
222
  LoadShedding.active = (LoadShedding.schedule.active || LoadShedding.event.active)
176
223
  if (LoadShedding.schedule.active) {
177
224
  LoadShedding.type = 'schedule'
@@ -243,4 +290,23 @@ module.exports = function (RED) {
243
290
  return res.send({ error: error.message })
244
291
  })
245
292
  })
293
+ RED.httpNode.get('/eskomsepush/api', (req, res) => {
294
+ if (!req.query.token) {
295
+ res.setHeader('Content-Type', 'application/json')
296
+ return res.send('invalid')
297
+ }
298
+ const headers = {
299
+ token: req.query.token
300
+ }
301
+ const options = {}
302
+
303
+ res.setHeader('Content-Type', 'application/json')
304
+ axios.get('https://developer.sepush.co.za/business/2.0/api_allowance',
305
+ { params: options, headers }).then(function (response) {
306
+ return res.send(response.data)
307
+ })
308
+ .catch(error => {
309
+ return res.send({ error: error.message })
310
+ })
311
+ })
246
312
  }