initial commit
This commit is contained in:
commit
6f1b1fa649
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
node_modules/
|
||||||
|
config.json
|
2613
package-lock.json
generated
Normal file
2613
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
17
package.json
Normal file
17
package.json
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"name": "wetterkram",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "src/index.mjs",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node --experimental-json-modules src/index.mjs"
|
||||||
|
},
|
||||||
|
"author": "Flummi",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"mariadb": "^2.5.4",
|
||||||
|
"sharp": "^0.28.3",
|
||||||
|
"slimbot": "^5.1.0",
|
||||||
|
"superagent": "^6.1.0"
|
||||||
|
}
|
||||||
|
}
|
5
src/graph.mjs
Normal file
5
src/graph.mjs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import graph from "./inc/graph.mjs";
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
console.log(await graph("pressure"));
|
||||||
|
})();
|
88
src/inc/graph.mjs
Normal file
88
src/inc/graph.mjs
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
import sql from "./sql.mjs";
|
||||||
|
import cfg from "../../config.json";
|
||||||
|
import lib from "./lib.mjs";
|
||||||
|
import sharp from "sharp";
|
||||||
|
import superagent from "superagent";
|
||||||
|
import { spawn } from "child_process";
|
||||||
|
|
||||||
|
const types = {
|
||||||
|
temperature: "Temperature (°C)",
|
||||||
|
humidity: "Humidity (%)",
|
||||||
|
pressure: "Pressure (hPa)",
|
||||||
|
gas: "Gas (KOhms)",
|
||||||
|
light: "Light"
|
||||||
|
};
|
||||||
|
|
||||||
|
const gnuplot = (q, _buf = []) => new Promise((resolve, reject) => {
|
||||||
|
const plot = spawn("gnuplot");
|
||||||
|
plot.stdin.write(Buffer.from(q));
|
||||||
|
plot.stdout.on('data', chunk => _buf.push(chunk));
|
||||||
|
plot.stdout.on('end', () => resolve(Buffer.concat(_buf)));
|
||||||
|
plot.stdout.on('error', err => reject(err));
|
||||||
|
});
|
||||||
|
|
||||||
|
export default async type => {
|
||||||
|
type = type.toLowerCase();
|
||||||
|
if(!Object.keys(types).includes(type)) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
msg: "unknown type"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const query = `
|
||||||
|
select
|
||||||
|
date_format(from_unixtime(sub.stamp), '%Y-%m-%d %H:%i:%S') as stamp,
|
||||||
|
sub.${type}
|
||||||
|
from (
|
||||||
|
select
|
||||||
|
stamp,
|
||||||
|
${type}
|
||||||
|
from weather_data_bme680
|
||||||
|
order by stamp desc
|
||||||
|
limit 300
|
||||||
|
) sub
|
||||||
|
order by stamp asc`;
|
||||||
|
|
||||||
|
let data = await sql.query(query);
|
||||||
|
data = lib.convertToCSV(["Time", type], data);
|
||||||
|
|
||||||
|
const q = `unset key
|
||||||
|
set term svg size 600,400
|
||||||
|
set datafile separator ","
|
||||||
|
set xlabel "Time"
|
||||||
|
set ylabel "${types[type]}"
|
||||||
|
set grid xtics lw 1 lc rgb "#dddddd"
|
||||||
|
set grid ytics lw 1 lc rgb "#dddddd"
|
||||||
|
set xtics rotate by 45 right
|
||||||
|
set xdata time
|
||||||
|
set timefmt "%Y-%m-%d %H:%M:%S"
|
||||||
|
format x "%H:%M:%S"
|
||||||
|
$D << EOD\n${data}\nEOD
|
||||||
|
plot for [col=2:2] $D using 1:col with lines
|
||||||
|
dump
|
||||||
|
quit\n`;
|
||||||
|
|
||||||
|
const out = await gnuplot(q);
|
||||||
|
|
||||||
|
const file = await sharp(out)
|
||||||
|
.flatten({ background: '#ffffff' })
|
||||||
|
.png()
|
||||||
|
.toBuffer();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = JSON.parse((await superagent
|
||||||
|
.post(`https://f0ck.space/upgraph.php`)
|
||||||
|
.field("topsecret", cfg.uploadkey)
|
||||||
|
.attach("image", file, "out.png")).text);
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
link: res.data.link
|
||||||
|
};
|
||||||
|
} catch(err) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
msg: err.msg
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
64
src/inc/lib.mjs
Normal file
64
src/inc/lib.mjs
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
export default new class {
|
||||||
|
calculateHeatIndexCelcius(temperature, humidity) {
|
||||||
|
return +(
|
||||||
|
-8.784695 + 1.61139411 * temperature + 2.33854900 * humidity +
|
||||||
|
-0.14611605 * temperature * humidity + -0.01230809 * temperature ** 2 +
|
||||||
|
-0.01642482 * humidity ** 2 + 0.00221173 * temperature ** 2 * humidity +
|
||||||
|
0.00072546 * temperature * humidity ** 2 +
|
||||||
|
-0.00000358 * temperature ** 2 * humidity ** 2
|
||||||
|
).toFixed(2);
|
||||||
|
};
|
||||||
|
|
||||||
|
calculateDewPointCelcius(temperature, humidity) {
|
||||||
|
return +(
|
||||||
|
243.04 * (Math.log(humidity / 100.0) + ((17.625 * temperature) / (243.04 + temperature))) /
|
||||||
|
(17.625 - Math.log(humidity / 100.0) - ((17.625 * temperature) / (243.04 + temperature)))
|
||||||
|
).toFixed(2);
|
||||||
|
};
|
||||||
|
|
||||||
|
getInline() {
|
||||||
|
return JSON.stringify({
|
||||||
|
inline_keyboard: [[
|
||||||
|
{ text: "📈 temperature", callback_data: 'g_temperature' },
|
||||||
|
{ text: "📈 pressure", callback_data: 'g_pressure' }
|
||||||
|
], [
|
||||||
|
{ text: "📈 light", callback_data: 'g_light' },
|
||||||
|
{ text: "📈 humidity", callback_data: 'g_humidity' }
|
||||||
|
], [
|
||||||
|
{ text: "📈 gas", callback_data: 'g_gas' },
|
||||||
|
{ text: "❌ remove graph", callback_data: 'g_remove' }
|
||||||
|
]]
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
getOutput(tmp) {
|
||||||
|
if(!tmp)
|
||||||
|
return ["no data"];
|
||||||
|
return [
|
||||||
|
`Temperature: ${tmp.temperature.toFixed(2)} °C (feels like ${this.calculateHeatIndexCelcius(tmp.temperature, tmp.humidity).toFixed(2)} °C)`,
|
||||||
|
`Dewpoint: ${this.calculateDewPointCelcius(tmp.temperature, tmp.humidity).toFixed(2)} °C`,
|
||||||
|
`Humidity: ${tmp.humidity.toFixed(2)}%`,
|
||||||
|
`Pressure: ${tmp.pressure.toFixed(2)} hPa`,
|
||||||
|
`Gas: ${tmp.gas} KOhms`,
|
||||||
|
`Altitude: ~${tmp.altitude.toFixed(2)} m`,
|
||||||
|
`Light: ${tmp.light}`,
|
||||||
|
``,
|
||||||
|
`Timestamp: ${tmp.date}`
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
convertToCSV(legend, objArray) {
|
||||||
|
const array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray;
|
||||||
|
let str = legend.join(",") + "\n";
|
||||||
|
for(let i = 0; i < array.length; i++) {
|
||||||
|
let line = '';
|
||||||
|
for(let index in array[i]) {
|
||||||
|
if(line != '')
|
||||||
|
line += ','
|
||||||
|
line += array[i][index];
|
||||||
|
}
|
||||||
|
str += line + '\n';
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
};
|
||||||
|
};
|
4
src/inc/sql.mjs
Normal file
4
src/inc/sql.mjs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
import mariadb from "mariadb";
|
||||||
|
import cfg from "../../config.json";
|
||||||
|
|
||||||
|
export default mariadb.createPool(cfg.sql);
|
81
src/index.mjs
Normal file
81
src/index.mjs
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
import slimbot from "slimbot";
|
||||||
|
import net from "net";
|
||||||
|
import cfg from "../config.json";
|
||||||
|
import sql from "./inc/sql.mjs";
|
||||||
|
import graph from "./inc/graph.mjs";
|
||||||
|
import lib from "./inc/lib.mjs";
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
const bot = new slimbot(cfg.bot[0].token);
|
||||||
|
const server = net.createServer();
|
||||||
|
let tmp;
|
||||||
|
|
||||||
|
server.on('connection', socket => {
|
||||||
|
socket.setEncoding('utf8');
|
||||||
|
console.log(`new connection: (${socket.remoteFamily}) ${socket.remoteAddress}:${socket.remotePort}`);
|
||||||
|
let tt = null;
|
||||||
|
let data = "";
|
||||||
|
let model = "";
|
||||||
|
|
||||||
|
socket.on('data', d => {
|
||||||
|
data += d;
|
||||||
|
tt = null;
|
||||||
|
tt = setTimeout(() => {
|
||||||
|
if(data.length <= 5)
|
||||||
|
return data = "";
|
||||||
|
try {
|
||||||
|
console.log("data", data.trimEnd());
|
||||||
|
data = JSON.parse(data);
|
||||||
|
if(data?.type === "ident")
|
||||||
|
model = data.model;
|
||||||
|
|
||||||
|
if(data?.data && model) {
|
||||||
|
tmp = { ...data.data, date: new Date().toLocaleString("de-DE") };
|
||||||
|
sql.query(`insert into weather_data_${model} (temperature, humidity, pressure, gas, light) values (?, ?, ?, ?, ?)`, [
|
||||||
|
tmp.temperature,
|
||||||
|
tmp.humidity,
|
||||||
|
tmp.pressure,
|
||||||
|
tmp.gas,
|
||||||
|
tmp.light
|
||||||
|
]).then(() => {});
|
||||||
|
}
|
||||||
|
} catch(err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
data = "";
|
||||||
|
return;
|
||||||
|
}, 300);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
bot.on("message", async e => {
|
||||||
|
if(!e.text || !tmp)
|
||||||
|
return false;
|
||||||
|
if(!e.text.startsWith("/temp@keindevbot"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bot.sendMessage(e.chat.id, lib.getOutput(tmp).join("\n"), {
|
||||||
|
reply_to_message_id: e.message_id,
|
||||||
|
reply_markup: lib.getInline()
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
bot.on("callback_query", async q => {
|
||||||
|
if(!q.data)
|
||||||
|
return false;
|
||||||
|
let link = await graph(q.data.substring(2));
|
||||||
|
let output = lib.getOutput(tmp);
|
||||||
|
|
||||||
|
if(link.success)
|
||||||
|
output[output.length - 1] += `[](${link.link})`;
|
||||||
|
|
||||||
|
bot.editMessageText(q.message.chat.id, q.message.message_id, output.join("\n"), {
|
||||||
|
parse_mode: "markdown",
|
||||||
|
reply_markup: lib.getInline()
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
server.listen(3000);
|
||||||
|
bot.startPolling();
|
||||||
|
|
||||||
|
})();
|
Loading…
Reference in New Issue
Block a user