node-red-zenbus 1.0.5 → 1.0.7

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.
@@ -1,4 +1,21 @@
1
1
  [
2
+ {
3
+ "id": "flow1",
4
+ "type": "tab",
5
+ "label": "Zenbus Next Bus",
6
+ "disabled": false,
7
+ "info": ""
8
+ },
9
+ {
10
+ "id": "comment1",
11
+ "type": "comment",
12
+ "z": "flow1",
13
+ "name": "Zenbus Next Bus - Example",
14
+ "info": "Polls the Zenbus API every 10 seconds and outputs the next bus ETA.\n\nEdit the zenbus node to set your alias, itinerary and stop IDs.\nFind them in the URL at https://zenbus.net",
15
+ "x": 200,
16
+ "y": 100,
17
+ "wires": []
18
+ },
2
19
  {
3
20
  "id": "zenbus1",
4
21
  "type": "zenbus-next-bus",
@@ -28,12 +45,5 @@
28
45
  "x": 450,
29
46
  "y": 200,
30
47
  "wires": []
31
- },
32
- {
33
- "id": "flow1",
34
- "type": "tab",
35
- "label": "Zenbus Next Bus",
36
- "disabled": false,
37
- "info": ""
38
48
  }
39
49
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-red-zenbus",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "Real-time next bus ETA from Zenbus networks via direct API (protobuf)",
5
5
  "type": "commonjs",
6
6
  "bin": {
@@ -1,7 +1,7 @@
1
1
  <script type="text/javascript">
2
2
  RED.nodes.registerType('zenbus-next-bus', {
3
3
  category: 'location',
4
- color: '#8e6538',
4
+ color: '#DEB887',
5
5
  defaults: {
6
6
  name: { value: '' },
7
7
  alias: { value: '', required: true },
@@ -15,7 +15,11 @@
15
15
  label: function () {
16
16
  return this.name || 'zenbus ' + (this.alias || '');
17
17
  },
18
- paletteLabel: 'zenbus next bus'
18
+ labelStyle: function () {
19
+ return this.name ? 'node_label_italic' : '';
20
+ },
21
+ paletteLabel: 'zenbus next bus',
22
+ outputLabels: ['bus ETA data']
19
23
  });
20
24
  </script>
21
25
 
@@ -43,35 +47,35 @@
43
47
  </script>
44
48
 
45
49
  <script type="text/html" data-help-name="zenbus-next-bus">
46
- <p>Polls the <a href="https://zenbus.net">Zenbus</a> real-time API and outputs next bus ETA.</p>
50
+ <p>Polls the Zenbus real-time API and outputs next bus ETA for a configured stop.</p>
47
51
 
48
- <h3>Configuration</h3>
49
- <dl class="message-properties">
50
- <dt>Alias <span class="property-type">string</span></dt>
51
- <dd>Network alias (e.g. <code>gpso</code>). Found in the Zenbus URL.</dd>
52
- <dt>Itinerary <span class="property-type">string</span></dt>
53
- <dd>Itinerary ID from the Zenbus URL.</dd>
54
- <dt>Stop <span class="property-type">string</span></dt>
55
- <dd>Stop ID from the Zenbus URL.</dd>
56
- <dt>Interval <span class="property-type">number</span></dt>
57
- <dd>Poll interval in seconds (default 10).</dd>
58
- </dl>
59
-
60
- <h3>Output</h3>
52
+ <h3>Outputs</h3>
61
53
  <dl class="message-properties">
62
54
  <dt>payload.stop <span class="property-type">string</span></dt>
63
55
  <dd>Stop name.</dd>
64
56
  <dt>payload.line <span class="property-type">string</span></dt>
65
57
  <dd>Line code.</dd>
66
58
  <dt>payload.next <span class="property-type">object | null</span></dt>
67
- <dd>Next bus: <code>etaMinutes</code>, <code>distanceM</code>, <code>estimatedArrival</code>, <code>scheduledTime</code>, <code>isLive</code>.</dd>
68
- <dt>payload.secondBus <span class="property-type">object | null</span></dt>
69
- <dd>Second tracked bus (same fields), only when live distance is available.</dd>
59
+ <dd>Next bus with properties: <code>etaMinutes</code>, <code>distanceM</code>,
60
+ <code>estimatedArrival</code>, <code>scheduledTime</code>, <code>isLive</code>.</dd>
61
+ <dt class="optional">payload.secondBus <span class="property-type">object | null</span></dt>
62
+ <dd>Second tracked bus (same properties as <code>msg.payload.next</code>).</dd>
70
63
  <dt>payload.timestamp <span class="property-type">string</span></dt>
71
- <dd>ISO timestamp of the poll.</dd>
64
+ <dd>ISO 8601 timestamp of the poll.</dd>
72
65
  </dl>
73
66
 
74
- <h3>Finding your IDs</h3>
75
- <p>Open your stop on <a href="https://zenbus.net">zenbus.net</a>. The URL contains:</p>
67
+ <h3>Details</h3>
68
+ <p>This node polls the <a href="https://zenbus.net">Zenbus</a> API at the configured
69
+ interval and sends a message with the next bus ETA for the specified stop.</p>
70
+ <p>Configure the node with the <code>alias</code>, <code>itinerary</code> and
71
+ <code>stop</code> values found in the Zenbus URL:</p>
76
72
  <pre>https://zenbus.net/publicapp/web/{alias}?line=...&amp;stop={stop}&amp;itinerary={itinerary}</pre>
73
+ <p>The node status shows a green dot with the ETA when live tracking is available,
74
+ a yellow dot when using scheduled data, or grey when no bus is found.</p>
75
+
76
+ <h3>References</h3>
77
+ <ul>
78
+ <li><a href="https://zenbus.net">Zenbus</a> - real-time bus tracking platform</li>
79
+ <li><a href="https://github.com/gautric/node-red-zenbus">GitHub</a> - the node's repository</li>
80
+ </ul>
77
81
  </script>
@@ -6,35 +6,53 @@ module.exports = function (RED) {
6
6
 
7
7
  const interval = (config.interval || 10) * 1000;
8
8
 
9
+ node.status({ fill: 'yellow', shape: 'ring', text: 'connecting...' });
10
+
9
11
  import('./zenbus-core.mjs').then(({ createClient }) => {
10
12
  createClient({
11
13
  alias: config.alias,
12
14
  itinerary: config.itinerary,
13
15
  stop: config.stop,
14
16
  }).then(client => {
17
+ node.log('Zenbus client initialized for ' + config.alias);
18
+
15
19
  async function tick() {
16
20
  try {
17
21
  const data = await client.poll();
18
22
  node.send({ payload: data });
19
- node.status({
20
- fill: data.next?.isLive ? 'green' : 'yellow',
21
- shape: 'dot',
22
- text: data.next ? `${data.next.etaMinutes} min – ${data.next.distanceM} m` : 'no bus',
23
- });
23
+ if (data.next) {
24
+ const text = data.next.etaMinutes + ' min';
25
+ node.status({
26
+ fill: data.next.isLive ? 'green' : 'yellow',
27
+ shape: 'dot',
28
+ text: text,
29
+ });
30
+ } else {
31
+ node.status({ fill: 'grey', shape: 'ring', text: 'no bus' });
32
+ }
24
33
  } catch (e) {
25
34
  node.error(e.message);
26
- node.status({ fill: 'red', shape: 'ring', text: e.message });
35
+ node.status({ fill: 'red', shape: 'ring', text: 'error' });
27
36
  }
28
37
  timer = setTimeout(tick, interval);
29
38
  }
30
39
  tick();
31
40
  }).catch(e => {
32
- node.error(e.message);
41
+ node.error('Init failed: ' + e.message);
33
42
  node.status({ fill: 'red', shape: 'ring', text: 'init failed' });
34
43
  });
35
44
  });
36
45
 
37
- node.on('close', () => { if (timer) clearTimeout(timer); });
46
+ node.on('close', function (removed, done) {
47
+ if (timer) {
48
+ clearTimeout(timer);
49
+ timer = null;
50
+ }
51
+ if (removed) {
52
+ node.log('Zenbus node removed');
53
+ }
54
+ done();
55
+ });
38
56
  }
39
57
 
40
58
  RED.nodes.registerType('zenbus-next-bus', ZenbusNextBusNode);