-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.js
159 lines (130 loc) · 4.91 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/**
* OneTesselAway - OneBusAway for the Tessel 2
*
* Display: 2 lines w/ 16 characters each. Example display:
*
* ----------------
* 11. 03 15 45
* 12: 18 32 51
* ----------------
*
* Supports up to two routes and two stops.
*/
const express = require('express');
const http = require('http');
const {
updateArrivalInfoUntilStopped,
} = require('./src/oba-api/ArrivalsAPIUtils');
const constants = require('./src/Constants');
const { initEvents } = require('./src/EventUtils');
const { getLatestLogFromFile, initLogger } = require('./src/Logger');
const { getState, initGlobalState, setState } = require('./src/GlobalState');
const { initHardware } = require('./src/hardware');
// Initialize ------------------------------------------------------------------
// Set up logger
const log = initLogger(constants.LOGFILE);
log.info('Initializing OneTesselAway...');
// Should we enable the device, or run in web-only mode?
const DEVICE_ENABLED = process.env.DISABLE_DEVICE !== '1';
// Set up Express server for the web UI
const app = express();
const server = new http.Server(app);
// Set up the templating engine
app.set('view engine', 'ejs');
app.set('views', __dirname + '/views');
// Set up static file middleware
app.use('/static', express.static(__dirname + '/views/static'));
// Set up event system for sending data to the Web UI w/o refreshing the page
initEvents(server);
// Init global state for the server and the web UI
initGlobalState();
// Routing -------------------------------------------------------------
// Route to index. Render initial Web UI server-side.
app.get('/', (req, res) => {
log.info(
`IP address ${req.ip} requesting ${req.method} from path ${req.url}`,
);
const globalStateJson = JSON.stringify(getState(), null, 2);
res.render('index', {
// Supply the device logs on render. Must refresh to get new ones.
deviceLogs: getLatestLogFromFile(constants.LOGFILE, {
reverseLines: true,
}),
// Supply global state
globalState: globalStateJson,
// Inject current global state when the page is rendered server-side
injectGlobalState: `<script>const globalState = ${globalStateJson}</script>`,
// Inject constants file to the Web UI to make hardware simulation
// easier
injectConstants: `<script>const constants = ${JSON.stringify(
constants,
null,
2,
)}</script>`,
// Initial LCD screen contents
lcdScreenLines: getState('lcdScreenLines'),
});
});
// Endpoint that returns OneBusAway arrival example responses for testing
app.get('/eg-oba-api-response/:stopId/:exampleResponse', (req, res) => {
const stopId = req.params.stopId;
const getEgRespPath = egRespName =>
`${__dirname}/src/oba-api/example-responses/${stopId}/${egRespName}.json`;
let egRespName = req.params.exampleResponse;
let egRespPath = getEgRespPath(egRespName);
let egResp;
try {
egResp = require(egRespPath);
} catch (e) {
log.warn(
`Example OneBusAway response file not found: ${egRespPath} Using default.`,
);
egRespPath = getEgRespPath('default');
egResp = require(egRespPath);
}
log.info(`Returning example OneBusAway response from "${egRespPath}"`);
res.json(egResp);
});
// Start -----------------------------------------------------------------------
// Initialize hardware and set up update loop. Needs to be wrapped in an async
// function to assure hardware is initialized and initial data is fetched
// before starting
(async () => {
if (DEVICE_ENABLED) {
log.info('Initializing hardware...');
} else {
log.info('Hardware is DISABLED, starting Web UI only...');
}
// Initialize all hardware, even when in "web-only" mode
await initHardware({
isDeviceEnabled: DEVICE_ENABLED,
pinsAndPorts: constants.PINS_AND_PORTS,
});
// Begin updating arrival info and LCD screen regularly
log.info('Starting OneTesselAway...');
log.info(
`Begin updating arrival info ${
DEVICE_ENABLED ? 'and LCD screen ' : ''
}every ${constants.API_UPDATE_INTERVAL} milliseconds`,
);
if (DEVICE_ENABLED) {
setState('lcdScreenLines', ['Getting bus', 'arrival info...']);
}
// Wait for the first arrival info to return before starting up, then
// continue to fetch at the specified interval
const stopUpdatingArrivalInfo = await updateArrivalInfoUntilStopped(
constants.API_UPDATE_INTERVAL,
);
// Start up web UI server
server.listen(constants.WEB_UI_PORT);
log.info(
`Web UI server address: ${constants.WEB_UI_ADDRESS}:${constants.WEB_UI_PORT}`,
);
// Shut down everything on ^C
process.on('SIGINT', () => {
log.info('Shutting down...');
stopUpdatingArrivalInfo();
server.close();
process.exit(0);
});
})();