initial commit

This commit is contained in:
Flummi 2021-07-01 17:25:51 +02:00
commit 6f1b1fa649
9 changed files with 2882 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
node_modules/
config.json

2613
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

17
package.json Normal file
View 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
View File

@ -0,0 +1,5 @@
import graph from "./inc/graph.mjs";
(async () => {
console.log(await graph("pressure"));
})();

88
src/inc/graph.mjs Normal file
View 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
View 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
View 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
View 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();
})();

8
start.sh Executable file
View File

@ -0,0 +1,8 @@
#!/bin/bash
while true
do
npm start
sleep 1
done