ctucx.git: smartie-pwa

[js] smarthome web-gui

commit a5749f61beb532f02141fc3cdeff8395ca816476
parent 9ce981278f4e692959eec3c6f5a9b4ce02595867
Author: Milan Pässler <me@pbb.lc>
Date: Fri, 14 Jun 2019 15:38:52 +0200

move to apu
9 files changed, 187 insertions(+), 197 deletions(-)
M
index.html
|
2
+-
R
websocket-relay/.gitignore -> server/.gitignore
|
0
A
server/index.js
|
181
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
R
websocket-relay/package.json -> server/package.json
|
0
R
websocket-relay/yarn.lock -> server/yarn.lock
|
0
M
src/layout.js
|
6
+++---
M
src/state.js
|
2
+-
M
sw.js
|
2
+-
D
websocket-relay/server.js
|
191
-------------------------------------------------------------------------------
diff --git a/index.html b/index.html
@@ -15,6 +15,6 @@ body {
 	<body>
 		<smarthome-layout></smarthome-layout>
 		<noscript>JavaScript is required to use Smart Home</noscript>
-		<script type="module" src="main.js"></script>
+		<script type="module" src="main.min.js"></script>
 	</body>
 </html>
diff --git a/websocket-relay/.gitignore b/server/.gitignore
diff --git a/server/index.js b/server/index.js
@@ -0,0 +1,181 @@
+"use strict";
+
+const url       = require("url");
+const http      = require("http");
+const net       = require("net");
+const modbus    = require("modbus-tcp");
+const WebSocket = require("ws");
+const fetch     = require("node-fetch");
+
+const state = {};
+
+function broadcastState() {
+	wss.broadcast(JSON.stringify(state));
+}
+
+const server = http.createServer(function(req, res) {
+	let requestUrl = url.parse(req.url);
+	if (req.method === "GET" && requestUrl.pathname === "/powermeter.json") {
+		res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
+		res.end(JSON.stringify(state.powermeter));
+	} else {
+		res.writeHead(404, { 'Content-Type': 'text/plain' });
+		res.end('404');
+	}
+});
+
+const wss = new WebSocket.Server({ server });
+
+wss.broadcast = function broadcast(data) {
+	wss.clients.forEach(function each(client) {
+		if (client.readyState === WebSocket.OPEN) {
+			client.send(data);
+		}
+	});
+};
+
+wss.on('connection', function connection(ws) {
+	ws.send(JSON.stringify(state));
+});
+
+setInterval(function sendKeepalive() {
+	wss.broadcast("");
+}, 1000);
+
+
+const client = new modbus.Client();
+const socket = new net.Socket();
+socket.on("close", function(e) {
+	console.log("reconnecting", e);
+	socket.setTimeout(300, function() {
+		socket.connect({'host': '192.168.1.1', 'port': 502 });
+	});
+});
+socket.connect({'host': '192.168.1.1', 'port': 502 });
+client.pipe(socket);
+
+/* lights */
+
+const lights = [
+	"Deckenbeleuchtung",
+	"Bett",
+	"Kueche",
+	"Bad",
+];
+
+wss.on('connection', function connection(ws) {
+	ws.on('message', function incoming(message) {
+		const input = String(message).split(' ');
+
+		if (input[0] == 'set' && input[1] < 9 && (input[2] == 'on' || input[2] == 'off')) {
+			let val = 0;
+
+			if (input[2] == 'on') {
+				val = 1;
+			}
+
+			setRelay(input[1], val);
+		}
+	});
+});
+
+function mapToNames(data) {
+	return lights.map((name, id) => {
+		return {
+			name,
+			id: id + 1,
+			value: data[id],
+		};
+	});
+}
+
+function setRelay(id, val) {
+	client.writeSingleCoil(10, '10'+id, val);
+	client.readCoils(10, 101, 108, function (err, data){
+		state.lights = mapToNames(data);
+		broadcastState();
+	})
+}
+
+function readRelays(ws) {
+	client.readCoils(10, 101, 108, function (err, data){
+		state.lights = mapToNames(data);
+	});
+}
+
+readRelays();
+
+/* powermeter */
+
+state.powermeter = {
+	60: { name: "Kueche" },
+	50: { name: "Sonstiges" },
+};
+
+const registers = {
+	voltage: 0,
+	power: 12,
+	frequency: 70,
+	import: 72,
+	cosphi: 30,
+};
+
+function unixTimestamp() {
+	return Math.floor(Number(new Date()) / 1000);
+}
+
+function round(num, places) {
+        const factor = Math.pow(10, places);
+        return Math.round(num * factor) / factor;
+}
+
+function getFloat32Register(counterId, registerId, client, socket) {
+	return new Promise(function(fulfill, reject) {
+		client.readInputRegisters(counterId, registerId, registerId+1, function (err, data) {
+			if (err) return reject();
+
+	// Create a buffer
+	var buf = new ArrayBuffer(4);
+	// Create a data view of it
+	var view = new DataView(buf);
+
+	// set bytes
+	view.setUint8(0, data[0][0]);
+	view.setUint8(1, data[0][1]);
+	view.setUint8(2, data[1][0]);
+	view.setUint8(3, data[1][1]);
+
+			//const buf = Buffer.concat(data).buffer;
+			//const view = new DataView(buf);
+			const num = view.getFloat32(0);
+
+			fulfill(num);
+		});
+	});
+}
+
+async function fetchValues() {
+	for (let [id, counter] of Object.entries(state.powermeter)) {
+		for (let key of Object.keys(registers)) {
+			try {
+				counter.values[key] = round(await getFloat32Register(id, registers[key], client, socket), 2);
+				counter.lastUpdated = unixTimestamp();
+			} catch(e) {}
+		}
+	}
+	broadcastState();
+}
+
+
+for (let [id, counter] of Object.entries(state.powermeter)) {
+	counter.values = Object.keys(registers).reduce(function(result, key) {
+		result[key] = 0;
+		return result;
+	}, {});
+	counter.lastUpdated = unixTimestamp();
+}
+
+setInterval(fetchValues, 20000);
+fetchValues();
+
+server.listen(8080);
diff --git a/websocket-relay/package.json b/server/package.json
diff --git a/websocket-relay/yarn.lock b/server/yarn.lock
diff --git a/src/layout.js b/src/layout.js
@@ -16,14 +16,14 @@ import "./settings.js";
 import "./spinner.js";
 import "./row.js";
 
-const luciRedirect = document.createElement("script");
-luciRedirect.innerHTML = "window.location = `http://${window.location.host}/cgi-bin/luci/`;";
+const netdataRedirect = document.createElement("script");
+netdataRedirect.innerHTML = "window.location = `http://${window.location.host}/netdata/`;";
 
 const pages = {
 	"#/lights": { name: "Lights", content: html`<smarthome-lights></smarthome-lights>`, icon: "lightbulb" },
 	"#/powermeter": { name: "Power Meter", content: html`<smarthome-power-meter></smarthome-power-meter><smarthome-power-meter-history></smarthome-power-meter-history>`, icon: "power" },
 	"#/departures": { name: "Departures", content: html`<smarthome-departures></smarthome-departures>`, icon: "departure_board" },
-	"#/luci": { name: "LuCI", content: html`<smarthome-spinner></smarthome-spinner> ${luciRedirect}`, icon: "router" },
+	"#/netdata": { name: "netdata", content: html`<smarthome-spinner></smarthome-spinner> ${netdataRedirect}`, icon: "show_chart" },
 	"#/settings": { name: "Settings", content: html`<smarthome-settings></smarthome-settings>`, icon: "settings" },
 };
 
diff --git a/src/state.js b/src/state.js
@@ -28,7 +28,7 @@ class State {
 	}
 
 	_initWS() {
-		this.ws = new WebSocket(`${window.location.protocol === "https:" ? "wss" : "ws"}://${window.location.hostname}/${window.location.pathname}/relay/ws`);
+		this.ws = new WebSocket(`${window.location.protocol === "https:" ? "wss" : "ws"}://${window.location.hostname}/${window.location.pathname}/ws`);
 		this.ws.onclose = () => {
 			this.connected = false;
 			this._initWS();
diff --git a/sw.js b/sw.js
@@ -9,7 +9,7 @@ let preCache = [
 	'https://fonts.gstatic.com/s/materialicons/v47/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2',
 ];
 
-const CACHE = 'cache-v5';
+const CACHE = 'cache-v6';
 
 self.addEventListener('install', function (evt) {
 	self.skipWaiting();
diff --git a/websocket-relay/server.js b/websocket-relay/server.js
@@ -1,191 +0,0 @@
-"use strict";
-
-const http      = require("http");
-const net       = require("net");
-const modbus    = require("modbus-tcp");
-const WebSocket = require("ws");
-const fetch     = require("node-fetch");
-
-const state = {};
-
-function broadcastState() {
-	wss.broadcast(JSON.stringify(state));
-}
-
-const server = http.createServer(function(req, res) {
-	let requestUrl = url.parse(req.url);
-	if (req.method === "GET" && requestUrl.pathname === "/powermeter.json") {
-		res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
-		res.end(JSON.stringify(state.powermeter));
-	} else {
-		res.writeHead(404, { 'Content-Type': 'text/plain' });
-		res.end('404');
-	}
-});
-
-const wss = new WebSocket.Server({ server });
-
-wss.broadcast = function broadcast(data) {
-	wss.clients.forEach(function each(client) {
-		if (client.readyState === WebSocket.OPEN) {
-			client.send(data);
-		}
-	});
-};
-
-wss.on('connection', function connection(ws) {
-	ws.send(JSON.stringify(state));
-});
-
-setInterval(function sendKeepalive() {
-	wss.broadcast("");
-}, 1000);
-
-/* lights */
-
-const lights = [
-	"Deckenbeleuchtung",
-	"Bett",
-	"Kueche",
-	"Bad",
-];
-
-wss.on('connection', function connection(ws) {
-	ws.on('message', function incoming(message) {
-		const input = String(message).split(' ');
-
-		if (input[0] == 'set' && input[1] < 9 && (input[2] == 'on' || input[2] == 'off')) {
-			let val = 0;
-
-			if (input[2] == 'on') {
-				val = 1;
-			}
-
-			setRelay(input[1], val);
-		}
-	});
-});
-
-function mapToNames(data) {
-	return lights.map((name, id) => {
-		return {
-			name,
-			id: id + 1,
-			value: data[id],
-		};
-	});
-}
-
-function setRelay(id, val) {
-	const client = new modbus.Client();
-	const socket = new net.Socket();
-
-
-	socket.connect({'host': '192.168.1.1', 'port': 502 });
-	client.pipe(socket);
-
-	client.writeSingleCoil(10, '10'+id, val);
-
-	client.readCoils(10, 101, 108, function (err, data){
-		state.lights = mapToNames(data);
-		broadcastState();
-	})
-
-	socket.end();
-}
-
-function readRelays(ws) {
-	const client = new modbus.Client();
-	const socket = new net.Socket();
-
-
-	socket.connect({'host': '192.168.1.1', 'port': 502 });
-	client.pipe(socket);
-
-	client.readCoils(10, 101, 108, function (err, data){
-		state.lights = mapToNames(data);
-	});
-
-	socket.end();
-}
-
-readRelays();
-
-/* powermeter */
-
-state.powermeter = {
-	60: { name: "Kueche" },
-	50: { name: "Sonstiges" },
-};
-
-const registers = {
-	voltage: 0,
-	power: 12,
-	frequency: 70,
-	import: 72,
-	cosphi: 30,
-};
-
-function unixTimestamp() {
-	return Math.floor(Number(new Date()) / 1000);
-}
-
-function getFloat32Register(counterId, registerId, client, socket) {
-	return new Promise(function(fulfill, reject) {
-		client.readInputRegisters(counterId, registerId, registerId+1, function (err, data) {
-			if (err) return reject();
-
-	// Create a buffer
-	var buf = new ArrayBuffer(4);
-	// Create a data view of it
-	var view = new DataView(buf);
-
-	// set bytes
-	view.setUint8(0, data[0][0]);
-	view.setUint8(1, data[0][1]);
-	view.setUint8(2, data[1][0]);
-	view.setUint8(3, data[1][1]);
-
-			//const buf = Buffer.concat(data).buffer;
-			//const view = new DataView(buf);
-			const num = view.getFloat32(0);
-
-			fulfill(num);
-		});
-	});
-}
-
-async function fetchValues() {
-	const client = new modbus.Client();
-	const socket = new net.Socket();
-
-
-	socket.connect({'host': '192.168.1.1', 'port': 502 });
-	client.pipe(socket);
-
-	for (let [id. counter] of Object.entries(state.powermeter)) {
-		for (let key of Object.keys(registers)) {
-			try {
-				counter.values[key] = await getFloat32Register(id, registers[key], client, socket);
-				counter.lastUpdated = unixTimestamp();
-			} catch(e) {}
-		}
-	}
-	socket.end();
-
-	broadcastState();
-}
-
-
-for (let [id, counter] of state.powermeter) {
-	counter.values = Object.keys(registers).reduce(function(result, key) {
-		result[key] = 0;
-		return result;
-	}, {});
-	counter.lastUpdated: unixTimestamp();
-}
-
-setInterval(fetchValues, 60000);
-fetchValues();
-
-server.listen(8080);