You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
101 lines
3.2 KiB
101 lines
3.2 KiB
/* tslint:disable:ordered-imports */ |
|
import "./configureAlias"; |
|
import "env"; |
|
import "./configureLogger"; |
|
|
|
import log from "@common/logger"; |
|
import * as mqtt from "@common/sprinklers/mqtt"; |
|
import { Server } from "http"; |
|
import * as WebSocket from "ws"; |
|
import app from "./app"; |
|
|
|
const mqttClient = new mqtt.MqttApiClient("mqtt://localhost:1883"); |
|
mqttClient.start(); |
|
|
|
import * as s from "@common/sprinklers"; |
|
import { sprinklersDeviceSchema } from "@common/sprinklers/json"; |
|
import * as ws from "@common/sprinklers/websocketData"; |
|
import { autorunAsync } from "mobx"; |
|
import { serialize } from "serializr"; |
|
const device = mqttClient.getDevice("grinklers"); |
|
|
|
app.get("/api/grinklers", (req, res) => { |
|
const j = serialize(sprinklersDeviceSchema, device); |
|
res.send(j); |
|
}); |
|
|
|
async function doDeviceCallRequest(data: ws.IDeviceCallRequest): Promise<any> { |
|
const { deviceName, method, args } = data; |
|
if (deviceName !== "grinklers") { |
|
// error handling? or just get the right device |
|
return; |
|
} |
|
switch (method) { |
|
case "runSection": |
|
return device.runSection(args[0], s.Duration.fromSeconds(args[1])); |
|
default: |
|
// new Error(`unsupported device call: ${data.method}`) // TODO: error handling? |
|
return; |
|
} |
|
} |
|
|
|
async function deviceCallRequest(socket: WebSocket, data: ws.IDeviceCallRequest): Promise<void> { |
|
let resData: ws.IDeviceCallResponse; |
|
try { |
|
const result = await doDeviceCallRequest(data); |
|
resData = { |
|
type: "deviceCallResponse", |
|
id: data.id, |
|
result: "success", |
|
data: result, |
|
}; |
|
} catch (err) { |
|
resData = { |
|
type: "deviceCallResponse", |
|
id: data.id, |
|
result: "error", |
|
data: err, |
|
}; |
|
} |
|
socket.send(JSON.stringify(resData)); |
|
} |
|
|
|
function webSocketHandler(socket: WebSocket) { |
|
const stop = autorunAsync(() => { |
|
const json = serialize(sprinklersDeviceSchema, device); |
|
log.info({ device: json }); |
|
const data = { type: "deviceUpdate", name: "grinklers", data: json }; |
|
socket.send(JSON.stringify(data)); |
|
}, 100); |
|
socket.on("message", (socketData: WebSocket.Data) => { |
|
if (typeof socketData !== "string") { |
|
return log.error({ type: typeof socketData }, "received invalid socket data type from client"); |
|
} |
|
let data: ws.IClientMessage; |
|
try { |
|
data = JSON.parse(socketData); |
|
} catch (err) { |
|
return log.error({ event, err }, "received invalid websocket message from client"); |
|
} |
|
switch (data.type) { |
|
case "deviceCallRequest": |
|
deviceCallRequest(socket, data); |
|
break; |
|
default: |
|
return log.warn({ data }, "received invalid client message type"); |
|
} |
|
}); |
|
socket.on("close", () => stop()); |
|
} |
|
|
|
const port = +(process.env.PORT || 8080); |
|
const host = process.env.HOST || "0.0.0.0"; |
|
|
|
const server = new Server(app); |
|
const webSocketServer = new WebSocket.Server({ server }); |
|
|
|
webSocketServer.on("connection", webSocketHandler); |
|
|
|
server.listen(port, host, () => { |
|
log.info(`listening at ${host}:${port}`); |
|
});
|
|
|