fb-dash/fbdash.c

218 lines
5.4 KiB
C

/*
* fbdash.c
*
* Adapted by Florian Klemenz for use in the fb_dash project
*
* Source and all credit goes to
* http://raspberrycompote.blogspot.com/
* --------------------------------------------------------------------------------------------
*
* http://raspberrycompote.blogspot.ie/2014/03/low-level-graphics-on-raspberry-pi-part_14.html
*
* Original work by J-P Rosti (a.k.a -rst- and 'Raspberry Compote')
*
* Licensed under the Creative Commons Attribution 3.0 Unported License
* (http://creativecommons.org/licenses/by/3.0/deed.en_US)
*
* Distributed in the hope that this will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <float.h>
#include <mysql.h>
#include "fblib.h"
#define WIDTH 240
#define HEIGHT 320
char *fbp = 0;
struct s_color {
unsigned char r;
unsigned char g;
unsigned char b;
};
typedef struct s_color color;
struct s_sourcedata {
char* text;
char* temperature;
char* humidity;
};
typedef struct s_sourcedata sourcedata;
void finish_with_error(MYSQL *con) {
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
void updateSlot(char *fbp, sourcedata data, int x_offset, int y_offset, color c) {
render_string(fbp, ubuntu_mono_24, data.text, x_offset, y_offset, c.r, c.g, c.b);
render_string(fbp, ubuntu_mono_48, data.temperature, x_offset + 115, y_offset - 9, c.r, c.g, c.b);
render_string(fbp, ubuntu_mono_48, "C", x_offset + 195, y_offset - 9, c.r, c.g, c.b);
render_string(fbp, ubuntu_mono_48, data.humidity, x_offset + 115, y_offset + 26, c.r, c.g, c.b);
render_string(fbp, ubuntu_mono_48, "%", x_offset + 195, y_offset + 26, c.r, c.g, c.b);
}
void updateData(char *fbp, int slot_height) {
// query database for latest values
printf("MySQL client version: %s\n", mysql_get_client_info());
MYSQL *con = mysql_init(NULL);
if (con == NULL) {
fprintf(stderr, "%s\n", mysql_error(con));
exit(1);
}
if (mysql_real_connect(con, "web-pi", "grafanaReader", "grafanaReader", "grafanaData", 0, NULL, 0) == NULL) {
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
char* query = "\
SELECT \
time, \
source, \
metric, \
value \
FROM readings AS r \
INNER JOIN sources AS s ON r.source_id = s.id \
INNER JOIN metrics AS m ON r.metric_id = m.id \
WHERE \
time > (NOW() - 60 * 15) AND \
metric IN ('Luftfeuchte','Temperatur') AND \
source IN ('Esszimmer','Wohnzimmer', 'Schlafzimmer', 'Abstellkammer') \
ORDER BY time DESC \
LIMIT 100;";
//printf("%s\n",query);
printf("Fetching data ...\n");
if (mysql_query(con, query)) {
finish_with_error(con);
}
MYSQL_RES *result = mysql_store_result(con);
if (result == NULL) {
finish_with_error(con);
}
// define what to display
sourcedata data[4] = {
{ "Esszimmer", NULL, NULL },
{ "Wohnzimmer", NULL, NULL },
{ "Schlafzimmer", NULL, NULL },
{ "Abstellkammer", NULL, NULL }
};
int num_fields = mysql_num_fields(result);
if (num_fields > 3) {
MYSQL_ROW row;
while ((row = mysql_fetch_row(result))) {
if (strlen(row[3]) > 4) row[3][4] = '\0'; // loose the secnod and third decimal ...
// data binding
for (int i = 0; i < 4; i++) {
if (strcmp(row[1], data[i].text) == 0) {
if (strcmp(row[2], "Temperatur") == 0 && data[i].temperature == NULL) data[i].temperature = row[3];
else if (strcmp(row[2], "Luftfeuchte") == 0 && data[i].humidity == NULL) data[i].humidity = row[3];
}
}
// debugging
//for(int i = 0; i < num_fields; i++) printf("%s ", row[i] ? row[i] : "NULL");
//printf("\n");
}
}
printf("Updating dashboard...\n");
for (int i = 0; i < 4; i++) {
color c = {255,125 + 25*i,25 + 25*i};
updateSlot(fbp, data[i], 15, 7 + slot_height * i, c);
}
printf("Done!\n");
mysql_free_result(result);
mysql_close(con);
}
void draw() {
clear_screen(fbp);
// horizontal spacersint x_space = 10;
int y_step_width = HEIGHT / 4;
for (int i = 1; i < 4; i++) {
int x0 = 15;
int x1 = WIDTH - x0;
int y = y_step_width * i;
int r = 225;
int g = 32;
int b = 32;
draw_line(fbp, x0, y-1, x1, y-1, r, g, b);
draw_line(fbp, x0, y , x1, y , r, g, b);
draw_line(fbp, x0, y+1, x1, y+1, r, g, b);
}
// fetch data from database and update screen
updateData(fbp, y_step_width);
}
// application entry point
int main(int argc, char* argv[])
{
int fbfd = 0;
long int screensize = 0;
// Open the framebuffer file for reading and writing
fbfd = open("/dev/fb1", O_RDWR);
if (fbfd == -1) {
printf("Error: cannot open framebuffer device.\n");
return(1);
}
printf("The framebuffer device was opened successfully.\n");
// map fb to user mem
screensize = WIDTH*HEIGHT*2;
fbp = (char*)mmap(0,
screensize,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fbfd,
0);
if ((int)fbp == -1) {
printf("Failed to mmap.\n");
}
else {
// draw...
draw();
}
// cleanup
//clear_screen(fbp);
munmap(fbp, screensize);
close(fbfd);
return 0;
}